详解js的作用域,预解析机制

  

虽然,ES6在我们工作中应用得越来越广泛,但是还是很多项目保留着ES5的写法,所以,今天,带着大家重新巩固下ES5下的作用域及预解析机制。

  

概念:
  

  

作用域:域,指的是一个空间,范围,区域,作用指的是在域内可进行读写操作。一个变量的作用域是程序源代码中定义的这个变量的区域。
  

  

在ES5中,只存在全局和函数级作用域,在ES6中,引入了块级作用域,js的预解析机制大概分为两个过程:预解析和自上而下逐行解读

  

预解析:js解析器会先把var定义的变量,函数,参数等一些东西存储进仓库里面(内存)。变量var在正式运行之前,都赋值为未定义,函数函数在运行之前,就是整个函数块
  

  

逐行解读
  

  

表达式=,+,-,*,/,+ +,———! % .....数量(),参数都可以赋值
  

  

遇到重名的,只留下一个,变量和函数重名,函数优先级高于变量,只留下函数
  

  

函数调用(函数是一个作用域,遇到作用域都会按照先进行预解析,然后逐行解读的过程执行),先局部找参数,局部找不到就自下向上找(作用域链)
  

  

概念扯了一大段,估计初学者还是有点晕乎乎,老司机就可以提前下车了,接下来,咋们举几个小栗子,结合上面的理论,深入理解。

  

实践
  

  

<>强例1:

        alert ();//错误:没有定义   =3;      

分析:   

预解析
  

  

上的面说过,预解析时只会把var,函数,参数等存储起来,所以:
  

  

整个作用域没有找到var函数参数

  

逐行解读
  

  

预解析后,内存中存在的且被赋值了underfind整个变量,所有,代码执行过程中程序直接报错。

  

<>强例2:

        alert ();//定义   var=3;      

分析:   

预解析
  

  

上的面说过,预解析时只会把var,函数,参数等存储起来,所以:
  

  

执行到第二行时,一个的值是未定义。

  

逐行解读
  

  

第一行:预解析后,内存中存在的且被赋值了underfined

  

<>强例3:

        alert ();//函数(){警报(4);}   var=1;   alert ();//1   函数(){警报(2);}   alert ();//1   var=3;   alert ();//3   函数(){警报(4);}   alert ();//3      

分析:   

域解析
  

  

上的面说过,预解析时只会把var,函数,参数等存储起来,所以:
  

  

执行到第二行时,一个的值是未定义。
  

  

执行到第四行时,一个的值是函数本身,也就是函数(){警报(2);}。
  

  

执行到第六行时,一个的值还是第四行时的值,也就是函数(){警报(2);},因为函数的优先级比变量高。
  

  

执行到第八行时,一个的值就变成了函数(){警报(4);},因为当两个函数重名时,遵循代码从上往下执行。

  

逐行解读
  

  

预解析完成之后,就是代码逐行执行了,
  

  

第一行:会弹出函数(){警报(4);},因为预解析完成之后,被存进内存的一个的值就是函数(){警报(4);}
  

  

第二行:第二行里有表达式,一个被赋了一个新的值1表达式会改变变量的值。表达式可以改变预解析的值。
  

  

第三行:现在被赋值为1,所有会弹出1
  

  

第四行:只是函数的声明,并没有用到表达式,而且也没有函数的调用,所以不会改变一个的值。
  

  

第五行:因为一个的值没有变化,所以还是1
  

  

第六行:使用了表达式,一个被赋了一个新的值3
  

  

第七行:会弹出3
  

  

第八行:函数的声明,不会改变一个的值。
  

  

第九行:一个的值没有改变,所以还是3
  

  

通过上面的栗子,相信大家应该对变量作用域的预解析过程有一定的了解了,接下来,咋们再举几个函数作用域的栗子

  

<>强例4:

        var=1;   函数fn1 () {   alert ();//定义   var=2;   }   fn1 ();   alert ()//1      

<>强例5:

        var=1;   函数fn1(一){   alert ();//1   var=2;   }   fn1(一个);   alert ()//1

详解js的作用域,预解析机制