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。