You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
alert(typeofeve);//结果:functionalert(typeofwalle);//结果:undefinedfunctioneve(){//函数定义式alert('I am Laruence');};varwalle=function(){//函数表达式}alert(typeofwalle);//结果:function
http://www.cnblogs.com/lhb25/archive/2011/09/06/javascript-scope-chain.html
http://www.laruence.com/2009/05/28/863.html
https://www.zhihu.com/question/36393048
读了上面三篇文章,对一直很困惑的作用域有了进一步的了解。真的很感谢博主们用心的写的博文和知友的回答。现在把里面能理解到相关知识都整合一起,方便以后理解。
有几个结论很重要
javascript的预编译( JS的预编译是以段为处理单元的)
JS在执行每一段JS代码之前, 都会首先处理var关键字和function定义式(函数定义式和函数表达式).
在调用函数执行之前, 会首先创建一个变量对象, 然后搜寻这个函数中的局部变量定义,和函数定义, 将变量名和函数名都做为这个变量对象的同名属性, 对于局部变量定义,变量的值会在真正执行的时候才计算, 此时只是简单的赋为undefined.
对于函数的定义:函数声明和函数表达式两种的区别
这就是函数定义式和函数表达式的不同, 对于函数定义式, 会将函数定义提前. 而函数表达式, 会在执行过程中才计算.(这就是说函数的声明的定义函数的方式,有一个重要的特征就是函数声明提升,其意思是在执行代码之前,就会读取函数的声明)
JavaScript的作用域链
注意到, 因为函数对象的[[scope]]属性是在定义一个函数的时候决定的, 而非调用的时候。
此时我们只有一个执行环境那就是全局执行环境。里面有一个func对象,其值是未定义的。func()函数未调用之前会创建一个执行环境-------而每个执行环境都有与之关联的变量对象(变量对象就是执行环境中包含了所有变量和函数的对象。另外变量对象是后台的,保存在内存中的,代码无法直接访问的)----------这个变量对象的有一个特殊的内部属性[scope]--------这个属性就是的就是作用域链的值。(这些关系都是静态的话,还没有开始执行,这只是这个函数拥有的关系)。
我们调用func()函数----------会创建一个执行环境-------而每个执行环境都有与之关联的活动对象(变量对象就是执行环境中包含了所有变量和函数的对象。另外活动对象是后台的,保存在内存中的,代码无法直接访问的)----------这个活动对象的有一个特殊的内部属性[scope]--------这个属性就是
的就是作用域链的值。此时全部执行环境的活动变量处于第二位,当前的执行环境的活动对象处于第一位。
在发生标识符解析的时候, 就会逆向查询当前scope chain列表的每一个活动对象的属性,如果找到同名的就返回。找不到,那就是这个标识符没有被定义。
作用域链例子
以上代码的最开始的作用域链和执行环境:
![zyy-05](https://cloud.githubusercontent.com/assets/15865210/16911011/a625d0c0-4d0e-11e6-886b-b0d1ab6aac57.jpg)
![zyy-06](https://cloud.githubusercontent.com/assets/15865210/16911026/b9814e42-4d0e-11e6-95e5-54b018a3d061.jpg)
![zyy-07](https://cloud.githubusercontent.com/assets/15865210/16911041/dbb042d4-4d0e-11e6-9d6f-aef2f4984e00.jpg)
我们先开始调用returnfunc()函数,马上会创建一个包含returnfunc()变量对象的行环境,作用域链开始变化,如下图:
随后returnfunc()函数会返回它内部的匿名函数,当匿名函数被返回后,整个作用域链和执行环境又发生了变化:
我们看到匿名函数(闭包)被添加到了最作用域链的最前端,returnfunc()的执行环境被销毁,但我们注意到returnfunc()函数的活动对象仍然在被引用(匿名函数仍在访问propertyName参数),因此returnfunc()函数的变量对象仍然在内存中,成为活动对象。这就是为什么匿名函数就能访问returnfunc()函数定义的所有变量和全局环境定义的变量,毕竟returnfunc()的活动对象仍然保持“激活”状态。
知道匿名函数被销毁,returnfunc()函数活动对象才被销毁
js预编译的例子(这个例子很重要,要重点理解)
因为js预编译----- 在调用函数执行之前, 会首先创建一个变量对象, 然后搜寻这个函数中的局部变量定义,和函数定义, 将变量名和函数名都做为这个变量对象的同名属性, 对于局部变量定义,变量的值会在真正执行的时候才计算, 此时只是简单的赋为undefined. 这句话很重要,要再提醒一遍。
开始执行echo()函数的时候,js预编译的时候,name设置了undefine,执行的echo()函数的时候,函数内部定义的变量name赋值了,即找到了,所以弹出eve,而age根本就没定义,所以会报错。
The text was updated successfully, but these errors were encountered: