JavaScript语言核心(二)--作用域链[[scope]] 及 执行对象 EC
- 作用域是关于引擎如何寻找变量以及会在何处找到变量的规则
执行上下文EC (栈结构) 和 说明的环境 作用域链表
作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。变量没有在函数内声明或者声明的时候没有带var就是全局变量,拥有全局作用域,window对象的所有属性拥有全局作用域;在代码任何地方都可以访问,函数内部声明并且以var修饰的变量就是局部变量,只能在函数体内使用,函数的参数虽然没有使用var但仍然是局部变量。
单纯的JavaScript作用域还是很好理解的,在一些类C编程语言中花括号内的每一段代码都有各自的作用域,而且变量在声明它们的代码段外是不可见的,称之为块级的作用域,JavaScript容易让初学者误会的地方也在于此,JavaScript并没有块级的作用域,只有函数级作用域:变量在声明它们的函数体及其子函数内是可见的。(较类C语言比较大的区别,允许嵌套的定义函数)。
JS权威指南中有一句很精辟的描述: ”JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里.”
来分析下JS代码的执行流程,Js本身是单线程的,每当有function被执行时,就会产生一个新的上下文(execution context),这一上下文会被压入Js的上下文堆栈(context stack)中,function执行结束后则被弹出,因此Js解释器总是在栈顶上下文中执行。在生成新的上下文时,首先会绑定该上下文的变量对象(variable object,VO),其中包括arguments和该函数中定义的变量;之后会创建属于该上下文的作用域链(scope chain),最后将this赋予这一function所属的Object。
函数也是对象,它有一个供JS引擎浏览的内部属性,叫[[Scope]]。该作用域是在函数定义时决定,而不是函数调用时决定。定义一个函数:不仅包含函数的代码逻辑,还必须引用当前的作用域链 Scope Chain
作用域第一个对象始终是function所在环境的变量对象(VO),function a所在的环境是是在全局windows。
由于a是函数,所以会继续将,函数内定义的 局部变量 压入ScopeChain的顶端,此时局部变量的值没有只是声明,并没有初始化。
函数调用:产生新的执行上下文,并将变量对象中的值,用来初始化Activation object中的属性。之后将 函数的ScopeChain 赋值给 Execution context的[[scope]]属性。运行过程中的符号就沿该ScopeChain来查找。
函数体内的变量,存储在函数定义时的作用域内。这种特性称为闭包。
for(var i = 0 ;i < elements.length;i++){ (founction(n){ elements[n].OnClick = founction(){ elert(n); } })(i); } //output: 0,1,2,3,..
应当明白,注册的响应函数的作用域里,各自保存的单独一份n。
PS:Learning about what functions
are and how scope works is the most important thing in Javascript.