1.什么是闭包?
闭包是指能够访问自由变量的函数。在JavaScript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数”。要能够彻底了解闭包首先要先理解什么是作用域和作用域链。
1.1作用域与作用域链
作用域就是指变量的有效范围,分为全局作用域和局部作用域。作用域就是指一对大括号 { } 之间的区域就是一个作用域。当有一对大括号出现的时候就形成了一个局部作用域,所以所有大括号的最外层就是全局作用域。在浏览器中,全局作用域就是window对象。
而作用域链就是当有多个大括号进行嵌套时,就形成了作用域链。作用域链具有继承性质,内层的局部作用域可以访问外层的作用域中定义的变量和函数,而外层的作用域无法访问内层的局部作用域中定义的变量和函数。
function funA(){
var a = 1
}
funA()
console.log(a); // 由原理外层函数无法访问内层函数定义的局部变量,故输出报错
var b = 2
function funB(){
console.log(b); // 输出2,局部作用域可以访问外层作用域中定义的变量,具有继承性
}
funB()
即当内层函数的内部访问了外层函数中的定义的变量或函数就形成了闭包。
function funA(){
var a = 1
function funB(){
console.log( a++ ); // 访问了外层作用域中的变量a,就形成了闭包
}
return funB
}
var aa = funA()
aa()
2.闭包的特点
1.闭包最大的特点就是其中的变量并不会被回收,而是常驻在内存当中,类似于全局变量。
function funA(){
var a = 1;
console.log(++a); // 输出2, 2, 2
}
for (let i = 0; i < 3; i++) {
funA()
}
/*
每次执行完函数时,其中的变量会被回收销毁,
下次执行时变量会被重新定义,所以每次输出的结果都是一样的
*/
function funA(){
var a = 1;
function funB(){
console.log(++a); // 输出2, 3, 4
}
return funB
}
var aa = funA()
for (let i = 0; i < 3; i++) {
aa()
}
/*
由于形成了闭包,funB中使用的变量 a 会常驻于内存中,并不会被销毁,
所以下次执行的时候读取了内存当中的上次被修改过后的变量 a ,
形成了类似于全局变量那样的存在
*/
2.从上方代码中可以看到,在for循环的这个作用域当中访问到了函数funB作用域中的变量,所以闭包的另一大特点就是打破了外层作用域无法访问内层作用域的这个限制,即通过闭包外层作用域可以访问其中的局部作用域的变量。
3.使用闭包的注意点
由于闭包会常驻于内存当中这一大特点,如果闭包使用不当的话就会消耗大量的内存空间,所以不要滥用闭包,否则会非常影响页面的性能。所以在使用完闭包之后一定要将其销毁。
function funA(){
var a = 1;
function funB(){
console.log(++a);
}
return funB
}
var aa = funA()
for (let i = 0; i < 3; i++) {
aa()
}
aa = null // 将闭包进行销毁