摘要:正式由于作用域链的这种关系,我们就不难理解,为什么和不能通过作用域链向上搜索,因为对和的搜索在当前执行函数的活动对象就停止了。
对于Javascript程序员来说,闭包总会让你觉得既熟悉又陌生,然而它对于开发人员来说却非常重要,javascript里的许多设计模式中都用到了闭包,此处以函数作用域为例。
//示例代码 var a=1; function foo(){ var b=2; console.log(a); function bar(){ var c=123; console.log(b); } bar(); } foo();
任何函数定义的时候,都会创建一个[[scope]]属性,这个对象对应的是一个对象的列表,列表中的对象仅能javascript内部访问,没法通过语法访问,用代码可以表示为:
1.函数定义时
在全局环境下定义了一个foo函数,此时foo函数的[[scope]]属性中只包含一个全局对象GO(global object)
//伪代码 //js代码默认进入全局执行环境,所以foo在初始时就被定义 foo.[[scope]]={ GO:{ this:window, window:{...}, document:{...}, a:undefined //此处是预编译,所以a并没有赋值 .... } } //当进入foo执行环境时,bar函数才被定义 bar.[[scope]]={ AO(foo):{ this:window, arguments:[], b:undefined }, GO:{ this:window, window:{...}, document:{...}, a:1 } }
2.函数被调用时
执行环境
在函数执行时,会创建一个叫做执行环境/执行上下文(execution context)的内部对象
它定义了一个函数执行时的环境
函数每次执行时的执行环境独一无二
多次调用函数就多次创建执行环境
并且函数执行完毕后,执行环境就会被销毁
执行环境有自己的作用域链,用于解析标识符
所以当foo函数被调用的时候,会创建foo执行环境,每个执行环境对应一个变量对象。首先会创一个它自己的活动对象【Activation Object】(这个对象中包含了this、参数(arguments)、局部变量(包括命名的参数)的定义,当然全局对象是没有arguments的)和一个变量对象的作用域链[[scope chain]],然后,把这个执行环境的[[scope]]按顺序复制到[[scope chain]]里,最后把这个活动对象推入到[[scope chain]]的顶部。这样[[scope chain]]就是一个有序的栈,这样保了对执行环境有权访问的所有变量和对象的有序访问。
//foo函数被调用时 foo.EC={ //foo的执行环境 AO:{ //foo的活动对象 this:window, arguments:[], b:undefined }, [[scope chain]]:{ AO:AO, //推入作用域链顶部的活动对象 GO:{...} //通过复制foo.[[scope]]得到的全局对象 } ... } //函数的作用域链 foo.EC.[[scope chain]]={ AO:{ this:window, arguments:[], b:undefined }, GO:{ this:window, window:{...}, document:{...}, a:1 } }
//当bar函数被调用时 bar.EC={ AO:{ this:window, arguments:[], c:undefined }, [[scope chain]]:{ AO:AO //推入作用域链顶部的活动对象 AO:{...} //foo活动对象 GO:{...} //全局活动对象 } }
3.函数代码执行阶段
var b=2 实际上就是对作用域链AO对象中的b进行赋值,当执行console.log(a)时候,遇到标识符a,就会根据标识符的名称在执行环境(Execution Context)的作用域链中进行搜索。从作用域链的第一个对象(该函数的Activation Object对象)开始,如果没有找到,就搜索作用域链中的下一个对象,如此往复,直到找到了标识符的定义。如果在搜索完作用域中的最后一个对象,也就是全局对象(Global Object)以后也没有找到,则会抛出一个错误,提示undefined。
正式由于作用域链的这种关系,我们就不难理解,为什么this和arguments不能通过作用域链向上搜索,因为对this和arguments的搜索在当前执行函数的活动对象就停止了。
以上是个人对于js作用域的理解, 如有错误欢迎讨论,本文未涉及with等改变作用域的行为
参考文章
http://www.cnblogs.com/pigtai...
http://blog.csdn.net/liujie19...
http://www.cnblogs.com/vadar/...
http://blog.csdn.net/q1056843...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/81114.html
摘要:下面,让我们以一个函数的创建和激活两个时期来讲解作用域链是如何创建和变化的。这时候执行上下文的作用域链,我们命名为至此,作用域链创建完毕。 JavaScript深入系列第五篇,讲述作用链的创建过程,最后结合着变量对象,执行上下文栈,让我们一起捋一捋函数创建和执行的过程中到底发生了什么? 前言 在《JavaScript深入之执行上下文栈》中讲到,当JavaScript代码执行一段可执行代...
摘要:开篇作用域是每种计算机语言最重要的基础之一,因此要想深入的学习作用域和作用域链就是个绕不开的话题。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。这时候执行上下文的作用域链,我们命名为至此,作用域链创建完毕。 开篇 作用域是每种计算机语言最重要的基础之一,因此要想深入的学习JavaScript,作用域和作用域链就是个绕不开的话题。 在《深入学习js之—-执行上下文栈》中我们提到...
摘要:每一个运行期上下文都和一个作用域链关联。这个对象将被推入作用域链的头部,这意味着函数的所有局部变量现在处于第二个作用域链对象中,因此访问代价更高了。在代码块内部,函数的所有局部变量将会被放在第二个作用域链对象中。 参考: Javascript作用域原理 理解 JavaScript 作用域和作用域链 JavaScript 作用域 作用域就是变量与函数的可访问范围,即作用域控制着变量与函数...
摘要:变量对象作用域链因为变量对象在执行上下文进入执行阶段时,就变成了活动对象,因此图中使用了来表示。 作用域 作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在 JavaScript 中,变量的作用域有全局作用域和局部作用域两种。JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。 静态作用域 函数的作用域在函数定义的时候...
摘要:变量对象作用域链因为变量对象在执行上下文进入执行阶段时,就变成了活动对象,因此图中使用了来表示。 作用域 作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在 JavaScript 中,变量的作用域有全局作用域和局部作用域两种。JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。 静态作用域 函数的作用域在函数定义的时候...
阅读 2570·2021-11-18 10:02
阅读 2263·2021-09-30 09:47
阅读 1683·2021-09-27 14:01
阅读 3090·2021-08-16 11:00
阅读 3147·2019-08-30 11:06
阅读 2369·2019-08-29 17:29
阅读 1496·2019-08-29 13:19
阅读 431·2019-08-26 13:54