javascript作用域原理学习

  在每次调用一个函数的时候,就会进入一个函数内的作用域,当从函数返回
以后,就会返回调用前的作用域。
  ECMA262关于作用域实现的描述:

任何执行上下文时刻的作用域,都是由作用域链(scope chain)来实现的。
在一个函数被定义的时候,会将它此时的作用域链链接到这个函数对象的[[scope]]属性。
在一个函数被调用时,会创建一个活动对象,然后对于函数的每一个形参,都命名为该活动对象的命名属性,然后将这个活动对象做为此时的作用域链最前端,并将这个函数的[[scope]]属性加入到作用域链中。

用例子说明。来自鸟哥的博客;

function factory() {
     var name = 'Elric';
     var intro = function(){
          alert('I am ' + name);
     }
     return intro;
}

function app(para){
     var name = para;
     var func = factory();
     func();
}

app('eva');

我是这么理解的:
因为

JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里.

所以,intro的作用域链应该是 intro --> factory --> window
当调用进入到intro时,对name的查找不会进入app的作用域,所以输出的值是Elric

再来一个例子。来自阮一峰老师的微博;

function a(x, y) {
    y = function(){
        x = 2;
    };
    return function() {
        var x = 3;
        y();
        console.log(x);
    }.apply(this, arguments);
}

a();// 3

我是这么理解的:
按照定义来,return的匿名函数的作用域链应该是[[scope]] --> a -->window
所以,在调用的时候,它最先找到的是自己的x的值,而执行y,修改的是a中的x的值。
如果把代码改成:

function a(x, y) {
    var x = 1;
    y = function() {
        x = 2;
    };
    return function() {
        y();
        console.log(x);
    }.apply(this, arguments);
}

a();// 2

这里输出的本来应该是1,但是!但是执行了y,y把a中的x修改成2.因为y的作用域链是y -->a -->window;

然后,在segmentfault上看到的

function a(x, y) {
    var name = 1;
    y = function() {
        x = 2;
    };
    return function() {
       var name = 3;
        y();
        console.log(this.x);
    }.apply(this, arguments);
}

a();// undefined

我简单的理解为,这里的this.x相当于window.x。所以是undefined。

总结:

JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里.
从定义出发去分析函数的作用域,而不是通过调用的顺序。

参考资料
1.鸟哥:Javascript作用域原理  
2.理解 JavaScript 作用域和作用域链
3.阮一峰老师微博上的关于js作用域的一道题


Elric_pp
69 声望0 粉丝