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

2019-03-26  本文已影响0人  下雨天_aa7b

作用域:变量的使用范围

//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}
   
上一篇下一篇

猜你喜欢

热点阅读