美文网首页
2019-03-26 JS中的作用域,作用域链,预解析

2019-03-26 JS中的作用域,作用域链,预解析

作者: 下雨天_aa7b | 来源:发表于2019-03-26 18:09 被阅读0次

    作用域:变量的使用范围

    //js中没有块级作用域---一对括号中定义的变量,这个变量可以在大括号外面使用
    if(true){
        var num3=1000;
        }
       console.log(num3);
    
     //函数中定义的变量是局部变量
     function f1() {
          //局部变量
          var num=10;
      }
        console.log(num);
    

    作用域链

      作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了
        层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错
       var num=10; //作用域链 级别:0
       var num2=20;
       var str = "abc"
       function f1() {
         var num2=20;
         function f2() {
           var num3=30;
           console.log(num);
         }
         f2();
       }
       f1();
    

    预解析

      //预解析:就是在浏览器解析代码之前,把变量的声明和函数的声明提前(提升)到该作用域的最上面
    
        //变量的提升==> 报undefined ,只是提升了变量并没将值提前
        console.log(num);
        var num=100;
    
        //函数的声明被提前了==> 函数声明先提前,但能执行
        f1();
        function f1() {
          console.log("这个函数,执行了");
        }
    
    //将变量赋值给一个函数,这样变量提升,同样可以执行
        var f2;
        f2=function () {
          console.log("你还呀");
        };
        f2();
    

    闭包

    闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包(这句话暂时不严谨)
        * 闭包的模式:函数模式的闭包,对象模式的闭包
        * 闭包的作用:缓存数据,延长作用域链
        * 闭包的优点和缺点:缓存数据
    
    
      函数模式的闭包:在一个函数中有一个函数
       function f1() {
         var num=10;
         //函数的声明
         function f2() {
           console.log(num);
         }
         //函数调用
         f2();
       }
       f1();
    
     对象模式的闭包:函数中有一个对象,可以访问函数中的变量
    
       function f3() {
         var num=10;
         var obj={
           age:num
         };
         console.log(obj.age);//10
       }
       f3();
    =============================
    function f2() {
          var num = 10;
          return function () {
            num++;
            return num;
          }
        }
        var ff = f2();
    //TODO: f2()函数调用是num = 10,然后赋值给ff,然后ff去调用,执行  return function () {
            num++;}每次执行ff,将num的数据缓存了
    
        console.log(ff());//11
        console.log(ff());//12
        console.log(ff());//13
    ================================================
    例子:用闭包实现点赞功能:
     <style>
            ul {
                list-style-type: none;
            }
            li {
                float: left;
                margin-left: 10px;
            }
            img {
                width: 200px;
                height: 180px;
            }
            input {
                margin-left: 30%;
            }
        </style>
        <head>
        <body>
            <ul>
                <li><img src="images/ly.jpg" alt=""><br /><input type="button" value="赞(1)"></li>
                <li><img src="images/lyml.jpg" alt=""><br /><input type="button" value="赞(1)"></li>
                <li><img src="images/fj.jpg" alt=""><br /><input type="button" value="赞(1)"></li>
                <li><img src="images/bd.jpg" alt=""><br /><input type="button" value="赞(1)"></li>
            </ul>
            <script>
                //获取所有的按钮
                //根据标签名字获取元素
                function my$(tagName) {
                    return document.getElementsByTagName(tagName);
                }
                //闭包缓存数据
                function getValue() {
                    var value = 2;
                    return function () {
                        //每一次点击的时候,都应该改变当前点击按钮的value值
                        this.value = "赞(" + (value++) + ")";
                    }
                }
                //获取所有的按钮
                var btnObjs = my$("input");
                //循环遍历每个按钮,注册点击事件
                for (var i = 0; i < btnObjs.length; i++) {
                    //注册事件
                    btnObjs[i].onclick = getValue();
                }
            </script>
    

    沙箱: 环境,黑盒,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世界

    简单理解:
       //沙箱---小环境
       (function () {
         var num=20;
         console.log(num+10);
       }());
    =========================================
    例子:
    <div>这是div</div>
    <div>这是div</div>
    <div>这是div</div>
    <p>这是p</p>
    <p>这是p</p>
    <p>这是p</p>
    <script>
      var getTag = 10;
      var dvObjs = 20;
      var pObjs = 30;
      (function () {
        //根据标签名字获取元素
        function getTag(tagName) {
          return document.getElementsByTagName(tagName)
        }
        //获取所有的div
        var dvObjs = getTag("div");
        for (var i = 0; i < dvObjs.length; i++) {
          dvObjs[i].style.border = "2px solid pink";
        }
        //获取所有的p
        var pObjs = getTag("p");
        for (var i = 0; i < pObjs.length; i++) {
          pObjs[i].style.border = "2px solid pink";
        }
      }());
      console.log(getTag);
      console.log(dvObjs);
      console.log(pObjs);
    </script>
    

    递归:函数中调用函数自己,此时就是递归,递归一定要有结束的条件

    //自己调用自己,给个结束条件,结束递归.
    var i = 0;
        function f1() {
          i++;
          if (i < 5) {
            f1();
          }
          console.log("从前有个山:");
    
        }
        f1();
    ======================================
    例子一: 求n个数字的和?用递归实现的规律是每次都每次都是这个数字减1的结果
    TODO: 实现1-5相加, 判断参数等于1就返回1,如果是2-5,return  x + Sum(x-1)
    
    //函数的声明:
    function Sum(x){
        if(x ==1){
            return 1;
        }
        return  x + Sum(x-1) //TODO: 这里也是自己调用自己,当x= 5,时,调用函数5-1,就是返回5+4.
    }
    //函数的调用:
        console.log(Sum(5))//给函数Sum传参数
        
     * 执行过程:
        * 代码执行getSum(5)--->进入函数,此时的x是5,执行的是5+getSum(4),此时代码等待
        * 此时5+getSum(4),代码先不进行计算,先执行getSum(4),进入函数,执行的是4+getSum(3),等待, 先执行的是getSum(3),进入函数,执行3+getSum(2),等待,先执行getSum(2),进入函数,执行 2+getSum(1);等待, 先执行getSum(1),执行的是x==1的判断,return 1,所以,
        * 此时getSum(1)的结果是1,开始向外走出去
        * 2+getSum(1) 此时的结果是:2+1
        * 执行:
        * getSum(2)---->2+1
        * 3+getSum(2) 此时的结果是3+2+1
        * 4+getSum(3) 此时的结果是4+3+2+1
        * 5+getSum(4) 此时的结果是5+4+3+2+1
        *可以理解为:进入房间,然后等着,然后我再出来
    ======================================================
    例子二:
    
        //递归案例:求一个数字各个位数上的数字的和:  123   --->6 ---1+2+3
        //523
        function getEverySum(x) {
          if(x<10){
            return x;
          }
          //获取的是这个数字的个位数
          return x%10+getEverySum(parseInt(x/10));
        }
       console.log(getEverySum(1364));//5
    
        //递归案例:求斐波那契数列
    
        function getFib(x) {
          if(x==1||x==2){
            return 1
          }
          return getFib(x-1)+getFib(x-2);
        }
        console.log(getFib(12));
    

    浅拷贝

       //浅拷贝:拷贝就是复制,就相当于把一个对象中的所有的内容,复制一份给另一个对象,直接复制,或者说,就是把一个对象的地址给了另一个对象,他们指向相同,两个对象之间有共同的属性或者方法,都可以使用
        
        
        var obj1={
          age:10,
          sex:"男",
          car:["奔驰","宝马","特斯拉","奥拓"]
        };
        //另一个对象
        var obj2={};
        
        //写一个函数,作用:把一个对象的属性复制到另一个对象中,浅拷贝
        //把a对象中的所有的属性复制到对象b中
        function extend(a,b) {
          for(var key in a){
            b[key]=a[key];
          }
        }
        extend(obj1,obj2);
        console.dir(obj2);//开始的时候这个对象是空对象
        console.dir(obj1);//有属性
    

    深拷贝

       //深拷贝:拷贝还是复制,深:把一个对象中所有的属性或者方法,一个一个的找到.并且在另一个对象中开辟相应的空间,一个一个的存储到另一个对象中
    
        var obj1={
          age:10,
          sex:"男",
          car:["奔驰","宝马","特斯拉","奥拓"],
          dog:{
            name:"大黄",
            age:5,
            color:"黑白色"
          }
        };
    
        var obj2={};//空对象
        //通过函数实现,把对象a中的所有的数据深拷贝到对象b中
        function extend(a,b) {
          for(var key in a){
            //先获取a对象中每个属性的值
            var item=a[key];
            //判断这个属性的值是不是数组
            if(item instanceof Array){
              //如果是数组,那么在b对象中添加一个新的属性,并且这个属性值也是数组
              b[key]=[];
              //调用这个方法,把a对象中这个数组的属性值一个一个的复制到b对象的这个数组属性中
              extend(item,b[key]);
            }else if(item instanceof Object){//判断这个值是不是对象类型的
         //如果是对象类型的,那么在b对象中添加一个属性,是一个空对象
              b[key]={};
              //再次调用这个函数,把a对象中的属性对象的值一个一个的复制到b对象的这个属性对象中
              extend(item,b[key]);
            }else{
              //如果值是普通的数据,直接复制到b对象的这个属性中
              b[key]=item;
            }
          }
        }
        extend(obj1,obj2);
        console.dir(obj1);
        console.dir(obj2);
    

    正则表达式

    正则表达式:也叫规则表达式,按照一定的规则组成的一个表达式,这个表达式的作用主要是匹配字符串的,
        * "我的电话:10086,他的电话:10010,你的电话:10000" 正则表达式,把这个字符串中的所有的数字找到
        *
        * 正则表达式的作用:匹配字符串的
        *
        * 在大多数编程语言中都可以使用
        *
        * 正则表达式的组成:是由元字符或者是限定符组成的一个式子
        *
        *
        * 元字符:
        *
        * .  表示的是:除了\n以外的任意的一个字符   "fdsfs238"
        *
        * [] 表示的是:范围,  [0-9] 表示的是0到9之间的任意的一个数字,  "789" [0-9]
        * [1-7] 表示的是1到7之间的任意的一个数字
        * [a-z] 表示的是:所有的小写的字母中的任意的一个
        * [A-Z] 表示的是:所有的大写的字母中的任意的一个
        * [a-zA-Z] 表示的是:所有的字母的任意的一个
        * [0-9a-zA-Z] 表示的是: 所有的数字或者是字母中的一个
        * [] 另一个函数: 把正则表达式中元字符的意义干掉    [.] 就是一个.
        * | 或者     [0-9]|[a-z] 表示的是要么是一个数字,要么是一个小写的字母
        * () 分组 提升优先级   [0-9]|([a-z])|[A-Z]
        * ([0-9])([1-5])([a-z]) 三组, 从最左边开始计算
        * (()(()))
        *
        *
        * 都是元字符,但是也可以叫限定符,下面的这些
        *    *   表示的是:前面的表达式出现了0次到多次
        *    [a-z][0-9]* 小写字母中的任意一个 后面是要么是没有数字的,要么是多个数字的
        *    "fdsfs3223323"  [a-z][0-9]*
        *
        *    +  表示的是:前面的表达式出现了1次到多次
        *    [a-z][9]+  小写字母一个后面最少一个9,或者多个9
        *    "fesfewww9fefds"
        *
        *    ?  表示的是:前面的表达式出现了0次到1次,最少是0次,最多1次 ,另一个含义:阻止贪婪模式
        *    [4][a-z]? "1231234ij"
        *  限定符:限定前面的表达式出现的次数
        *  {} 更加的明确前面的表达式出现的次数
        *  {0,} 表示的是前面的表达式出现了0次到多次,和 *一样的
        *  {1,} 表示的是前面的表达式出现了1次到多次,和 +一样的
        *  {0,1} 表示的是前面的表达式出现了0次到1次,和 ?一样的
        *  {5,10} 表示的是前面的表达式出现了5次到10次
        *  {4} 前面的表达式出现了4次
        *  {,10} 错误的========不能这么写
        *  ^ 表示的是以什么开始,或者是取非(取反) ^[0-9] 以数字开头
        *  ^[a-z] 以小写字母开始
        *  [^0-9] 取反,非数字
        *  [^a-z] 非小写字母
        *  [^0-9a-zA-Z_]
        *  $ 表示的是以什么结束   [0-9][a-z]$  必须以小写字母结束
        *  ^[0-9][a-z] 相当于是严格模式   "3f2432e"  "4f"
        *   \d 数字中的任意一个,
        *   \D 非数字中的一个
        *   \s 空白符中的一个
        *   \S 非空白符
        *   \w 非特殊符号
        *   \W 特殊符号
        *   \b 单词的边界
        *   "what are you no sha lei"
        *
    
        *    . 除了\n以外的任意一个单个字符
        *    []  范围
        *    () 分组,提升优先级
        *    | 或者
        *    * 0-多次
        *    + 1-多次
        *    ? 0-1次
        *    {0,} 和*一样
        *    {1,} 和+
        *    {0,1} 和?
        *
        *    \d 数字中的一个
        *    \D 非数字
        *    \s 空白符
        *    \S 非空白符
        *     \W  特殊符号
        *     \w 非特殊符号 _
        *     ^ 取反,以什么开始
        *     $ 以什么结束
       
             *     \b 单词边界
    
    

    练习: 学会使用工具:

    *
        * 写正则表达式,根据字符串来写正则表达式进行匹配
        *
        * 经验: 1.找规律 2.不要追求完美
    
        * 身份证的正则表达式
        *
        * 15位或者18位
        * ([1-9][0-9]{14})|([1-9][0-9]{16}[0-9xX])
      
        * ([1-9][0-9]{14})([0-9]{2}[0-9xX])?
      
        * 练习:
        * 1.座机号码的正则表达式
        * 010-19876754
        * 0431-87123490
        *
        * [0-9]{3,4}[-][0-9]{8}
        * \d{3,4}[-]\d{8}
        *
        * \d{3,4}[-][0-9]{8}
        * 2.qq号码的正则表达式
        *
        * [1-9][0-9]{4,10}
        * \d{5,11}
        *
        * 3.手机号码的正则表达式
        *
        * 130 131 132 133 134 135 136 137 138 139
        * 143 147
        * 150 151 152 153 154 155 156 157 158 159
        * 170 171 173 176 177
        * 180 181 182 183 184 185 186 187 188 189
        * ([1][358][0-9][0-9]{8})|([1][4][37][0-9]{8})|([1][7][01367][0-9]{8})
        * \d{11}
      
        * 邮箱的正则表达式,必须要记住的
        *
        * sd2113_3.-fd@itcast.com.cn
    
        * [0-9a-zA-Z_.-]+[@][0-9a-zA-Z_.-]+([.][a-zA-Z]+){1,2}
       
    

    相关文章

      网友评论

          本文标题:2019-03-26 JS中的作用域,作用域链,预解析

          本文链接:https://www.haomeiwen.com/subject/nsrgvqtx.html