Skip to content

作用域链

  1. VO中包含一个额外的属性,该属性指向创建该VO的函数本身
  2. 每个函数在创建时,会有一个隐藏属性[[scope]],它指向创建该函数时的AO
  3. 当访问一个变量时,会先查找自身VO中是否存在,如果不存在,则依次查找[[scope]]属性。

某些浏览器会优化作用域链,函数的[[scope]]中仅保留需要用到的数据。

js
    var g = 0;

    function A() {
        var a = 1;

        function B() {
            var b = 2;
            var C = function() {
                var c = 3;
                console.log(c, b, a, g);
            }
            C();
        }

        B();
    }

    A();

作用域链

闭包

js
    var a = 1;

    function A() {
        console.log(a);
    }

    function Special() {
        var a = 5;
        var B = A;
        B();
    }

    Special();

此处,B是一个闭包,函数A定义的时候的词法环境是a=1。

闭包记录的是函数定义时候的环境,而不是执行时候的环境。

面试题

如果一眼能看出来的,就无需复杂分析。如果一眼看不出来就是要绕的题,那么就画出执行栈去分析。

js
var foo = { n: 1 };
(function (foo) {
    console.log(foo.n); // 1
    foo.n = 3;
    var foo = { n: 2 };
    console.log(foo.n); // 2
})(foo);
console.log(foo.n); // 3
js
var food = "rice";
var eat = function () {
    console.log(`eat ${food}`);
};
(function () {
    var food = "noodle";
    eat();//eat rice
})();
js
var food = "rice";
(function () {
    var food = "noodle";
    var eat = function () {
        console.log(`eat ${food}`);
    };
    eat();//eat noodle
})();
js
function A() {
    for (var i = 0; i < 10; i++) {
        setTimeout(function () {
            console.log(i);//输出10次9
        }, 1000)
    }
}

A();


for (var i = 0; i < 3; i++) {
    (function (i) {
        setTimeout(function () {
            console.log(i); //1s输出0 1 2 因为此处使用闭包记录了词法环境
        }, 1000)
    }(i));
}

MIT License