Scope & Closures

JS 也是编译型语言,并不是边解释边执行的。
编译的时机是代码即将执行之前。
Hoisting

编译时 JS 会把函数和变量的声明提升到它们所在的 scope 的顶层

a = 2;
var a;
console.log( a ); // 2

等价于下面的代码

var a;
a = 2;
console.log( a );
console.log( a ); // undefined
var a = 2;

等价于下面的代码

var a;
console.log( a );
a = 2;
foo();

function foo() {
    console.log( a ); // undefined
    var a = 2;
}

同理 foo 和 a 的声明都被提升, 还是打印 undefined

Closure is when a function is able to remember and access its lexical scope even when that function is executing outside its lexical scope.
有点只可意会不可言传的感觉
闭包就是当一个函数在它的词法域之外执行的时候,仍然可以访问它所在的词法域(的变量和函数)
function foo() {
    var a = 2;

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

    return bar;
}

var baz = foo();

baz();

foo 返回了 bar 函数, foo 执行完毕后,baz 引用了返回的函数,这时再执行 baz 仍然可以访问到变量 a。 这里 baz 是在 global 域执行的而不是在 foo 域执行的。


for (var i=1; i<=5; i++) {
    setTimeout( function timer(){
        console.log( i );
    }, i*1000 );
}

将打印 5 个 6,i 会被提升到 global 域,每个 setTimeout 包围的都是 global 域中的 i

解决方案就是让每个 setTimeout 都包围自己的域中的变量

for (var i=1; i<=5; i++) {
    (function(){
        var j = i;
        setTimeout( function timer(){
            console.log( j );
        }, j*1000 );
    })();
}

每个 setTimeout 都包围在 function 形成的独立的域中,每个域中都有自己的变量 j。

你可能感兴趣的:(Scope & Closures)