个人理解:JS闭包就是让函数外部可以读取函数内部的变量。
理解JS闭包首先要理解几个前提:
1.变量的作用域。
首先变量的作用域比较容易理解。一个变量的作用域就是程序源代码中定义这个变量的区域!
例如:全局变量拥有全局作用域,在JS的代码中任何地方都是有定义。
函数内部声明的变量只在函数体内部有定义,是局部变量,作用域也是局部的。
var scope = "全局变量";
function cheak(){
var scope = "局部变量1"; //第一个局部变量赋值.这里必须有var 不然声明就成为了全局变量
console.log(scope);
return function chidren1(){
var scope = "局部变量2"; //第二个局部变量赋值.这里必须有var 不然声明就成为了全局变量
console.log(scope);
return function chidren2(){
var scope = "局部变量3"; //第三个局部变量赋值.这里必须有var 不然声明就成为了全局变量
console.log(scope)
}
}
}
2.作用域链。
如上所示,每一段JS代码(全局代码或者函数)都有一个相关联的作用域链。查找的时候就像是变量的解析一样。
例如:(上面代码成功的情况下)
var a = cheak(); //打印 局部变量1 并且a被chidren1赋值。
var b = a(); //打印 局部变量2 并且b被chidren2赋值。
var c = b(); //打印 局部变量3
假如 第二个局部变量赋值被删除了会怎么样?
这个时候
var a = cheak(); //打印 局部变量1 并且a被chidren1
var b = a(); //打印 局部变量1 并且a被chidren1赋值。
var c = b(); //打印 局部变量3 并且a被chidren1赋值。
上述例子作用域链的最前端含有局部变量3,向后查找是局部变量2,再向后是局部变量1,在后面是全局变量。这个顺序就是查找时候的顺序。当局部变量2不存在就会查找到局部变量1。如果整个作用域链都不存在就会报错。就如同直接
console.log(err); //Uncaught ReferenceError: err is not defined
总结一下就是(我都感觉绕,针对每个人简单理解好了)
作用域链的最前端始终是当前执行的代码所在环境的变量对象,下一个变量对象来自包含当前代码执行环境变量对象的环境,下一个变量对象来自包含环境的包含环境,依次往上,直到全局执行环境的变量对象。全局执行环境的变量对象始终是作用域链中的最后一个对象。
理解完上面就要说闭包了,这里简单的说(代码与上述代码独立不冲突)
上图函数内部可以访问外部变量
上图函数外部无法访问内部变量
如何让函数外部可以访问内部变量呢?
这就是函数闭包
外部需要使用内部的变量,内部变量无法释放内存,无法被浏览器的垃圾回收机制回收。所以使用的时候因为占用大量内存容易造成内存泄漏。
如果对闭包还是无法理解。个人推荐一本书《你不知道的JavaScript》书中所讲述的闭包更为详细,可以参考