作用域闭包
1. 概念
先来回忆一下词法作用域的概念:词法作用域就是定义在这个阶段的作用域,在你写代码时将变量和块作用域写在哪里来决定的。
当一个函数可以记住并访问所在的词法作用域的时候,就产生了闭包
function foo() {
var a = 2;
function bar() {
console.log(a); // 2
}
bar();
}
foo();
当执行bar函数的时候 console.log(a); 这个a是不在bar的作用域里面的,
但是它会往外部函数寻找,如果有,就拿来使用
bar对a的引用,是词法作用域的一种查找规则 这种规则只是闭包的一部分
像上面这种就是符合bar执行刚好在词法作用域内,然后可以访问这个a
下面来看看如果bar执行的时候不在词法作用域里面,以便我们更好的理解闭包
2. 更清楚的闭包
function foo() {
var a = 2;
function bar() {
console.log(a);
}
return bar; // 当执行了foo() 返回bar
}
// 当foo执行完之后 函数和里面的变量本应该消失的,但是由于产生了闭包
// bar在foo执行完之后,依旧可以使用foo的内部作用域
var baz = foo(); // 将bar作为一个值传给baz 执行
baz(); //2
// bar在定义的词法作用域外面执行了
无论使用何种方式对函数类型的值进行传递,当函数在别处被调用的时候都会产生闭包
function foo() {
var a = 2;
function baz() {
console.log(a);
}
bar(baz);
}
function bar(fn) {
fn(); // baz 在这里被执行了 也是在块级作用域外面被执行
}
function wait(message) {
setTimeout( function timer() {
console.log(message)
},1000);
}
wait("hell");
// 将一个内部函数名为timer传递给setTimeout(...) timer具有涵盖wait作用一的闭包
// 因此还保存有对便利message的引用
3. 循环和闭包
for (var i = 0;i <= 5;i++) {
setTimeout(function () {
console.log( i ); // i封闭在一个共享的全局作用域中,因此实际只有一个i
}, (i * 1000));
}
// 每次迭代都应该有一个作用域
var i;
for (i = 0;i <= 5;i++) {
setTimeout(function () {
console.log(i)
}, (i * 1000));
}
每隔一秒都是输出6
如果要实现输出1,2,3,4,5.
for (var i = 1;i <= 5;i++) {
(function(j) {
setTimeout(function timer() {
console.log(j)
},j * 1000)
})(i) // 每次都把i传进去
}
for (let i = 0;i <= 5;i++) {
setTimeout(function () {
console.log(i)
}, (i * 1000));
}