闭包
定义:闭包是指一个函数可以访问另一个函数作用域内的变量。
为什么会有闭包?
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
var foo = checkscope(); // foo指向函数f
foo(); // 调用函数f()
foo();执行的时候checkscope函数执行上下文已经销毁了,但是函数 f 的执行上下文会维持一个作用域链,这个作用域链指向checkscope作用域。
作用域链为: f 作用域 ==> checkscope作用域 ==> 全局作用域。
即使 checkscopeContext(执行上下文) 被销毁了,但是 JavaScript 依然会让 checkscopeContext.AO(活动对象) 活在内存中,f 函数依然可以通过 f 函数的作用域链找到它,这就是闭包实现的关键。
作用域链
当访问一个变量时,解释器会首先在当前作用域查找标示符,如果没有找到,就去父作用域找,直到找到该变量的标示符或者不在父作用域中,这就是作用域链。
闭包必刷题:
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
};
}
data[0]();
data[1]();
data[2]();
答案都是3 因为执行data[0]的时候,data[0]的作用域链为 data[0]==>全局作用域
由于它自身没有 i 就会向上查找,所有从全局上下文查找到i为3,data[1] 和 data[2] 是一样的。
解决办法,改成闭包:
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = (function (i) {
return function(){
console.log(i);
}
})(i);
}
data[0](); // 0
data[1](); // 1
data[2](); // 2
执行 data[0] 的时候函数的作用域链发生变化
函数作用域==> 匿名函数作用域 ==> 全局作用域
因为闭包执行上下文中贮存了变量i
,所以根据作用域链会在globalContext.VO
中查找到变量i
,并输出0。
变量提升
var scope="global";
function scopeTest(){
console.log(scope);
var scope="local"
}
scopeTest(); //undefined
//***********等同于*****************
var scope="global";
function scopeTest(){
var scope;
console.log(scope);
scope="local"
}
scopeTest(); //undefined
注意,如果在局部作用域中忘记var,那么变量就被声明为全局变量。