JavaScript作用域与作用域链

JavaScript作用域的笔记,包括函数作用域、执行环境、变量对象和作用域链的理解。

1  函数作用域

     javascript函数作用域:变量在声明它的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
     声明提前:js函数里声明的所有变量(但不涉及赋值),都被提前至函数体的顶部。
  • 当声明一个js全局变量时,实际上是定义了全局对象的一个属性。使用var声明一个变量时,该属性不可配置,即这个变量无法通过delete删除。

2 执行环境(执行上下文)

     理解执行环境:执行环境分为局部执行环境(方法执行环境)和全局执行环境,局部执行环境在方法执行完毕后就被销毁了,它里面的所有数据也将被回收栈收回(如果遇到闭包那么情况会有所变化,这时就需要闭包销毁时才会被销毁);而全局的执行环境则是在窗口关闭时才会被销毁。
      每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境被推入栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环 境。某个执行环境中的代码执行完后,该环境销毁,保存在其中的所有变量和函数定义也随之销毁。而全局执行环境直到应用程序退出才会被销毁。
     注意:每一个函数的调用(甚至递归)都会产生一个新的上下文环境。

3  变量对象

     每一个执行环境都有一个与之关联的变量对象,对于全局环境,是全局对象自身,对于函数,是活动对象。这个对象存储着在环境中定义的以下内容:
1. 函数的形参
2. var声明的变量
3. 函数声明(不包括函数表达式)
     这些数据,作为属性存储在变量对象中。
     活动对象:活动对象就是作用域链上正在被执行和引用的变量对象。
      函数内部都有一个叫做执行环境用于控制变量和函数的访问,函数内部所有的变量和函数都保存在一个叫做变量对象中(这部分是隐式的),变量对象被调用的时候就称之为活动对象,变量对象里面如果还有(函数)变量对象他们之间需要访问的这个时候又被称之为作用域链!一层层到全局执行环境!

4  作用域链

     作用域链:内部环境所有变量对象的列表,这组对象定义了这段代码“作用域”中的变量,保证程序在执行的时候按照一定的顺序访问变量。当查找变量x时(即变量解析),从链中第一个对象开始查找,若有该属性,则直接使用,若无,继续查找链上的下一个对象。以此类推,若链上午任何对象有属性x,则认为该段代码的作用域链上不存在x,抛出引用错误的异常。
     理解:
var func = function (lps, rps) {
    var name = 'john';
    ......
}
func("jack", 'lucy');
       在执行func定义语句的时候,会创建一个这个函数对象的[[scope]]属性,并将该属性,链接到定义它的作用域上,此时func定义在全局环境,所以此时[[scope]]只是指向全局活动对象。
[scope chain]] = [
{
     window call object
}]
    在调用func执行时, 会创建一个活动对象(假设为aObj, 由JS引擎预编译时刻创建),并创建arguments属性, 然后会给这个对象添加俩个命名属性aObj.lps, aObj.rps; 对于每一个在这个函数中申明的局部变量和函数定义, 都作为该活动对象的同名命名属性.
[[scope chain]] = [
{
     lps : 'jack',
     rps : 'lucy',
     name : undefined,
     arguments : []
}, {
     window call object
}
]            
     然后将调用参数赋值给形参数,对于缺少的调用参数,赋值为undefined。然后将这个活动对象做为scope chain的最前端, 并将func的[[scope]]属性所指向的,定义func时候的顶级活动对象, 加入到scope chain.
     有了上面的作用域链, 在发生标识符解析的时候, 就会逆向查询当前scope chain列表的每一个活动对象的属性,如果找到同名的就返回。找不到,那就是这个标识符没有被定义。
4.2  改变作用域链
      在代码执行阶段,有两个声明能修改作用域链:with声明和catch语句。它们添加到作用域链最前端。
     Scope = withObject|catchObject + AO|VO(变量/活动对象) + [[Scope]
var foo = {x: 10, y: 20};
with (foo) {
    alert(x); // 10
    alert(y); // 20
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注