目录
1、举例子
最简单的两个闭包例子:
// 闭包1
(function(a){
console.log(a) // 1
})(1)
// 闭包2
function fn(){
var a = 2
return function(){
console.log(a) // 2
}
}
fn()()
2、什么是闭包?
闭包:可以访问另一个函数作用域变量的函数。由于 javascript
的特性,外层的函数无法访问内部函数的变量;而内部函数可以访问外部函数的变量(即作用域链)
由于在 Javascript 语言中,只有函数内部的子函数才能读取该函数的局部变量,因此可以 把闭包简单理解成 “定义在一个函数内部的函数”。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以在函数外部读取内部的变量,另一个就是让这些变量的值始终保持在内存中。
在局部作用域引用上层作用域(非全局)的变量,就会形成闭包。闭包是当前作用域的延伸。
function a() {
var aaa = 100
function b() {
console.log(aaa) // 100
}
b()
}
a()
以上代码会形成闭包,但是没有返回出去,所以没有保持住。
在内部函数b中使用了外部函数a中的变量,这个变量就会作为闭包对象的属性。
function a() {
var aaa = 100
function b() {
console.log(b) // function(){}
}
b()
}
a()
以上代码会形成闭包,但是没有保持住。函数执行结束之后,就被销毁了。
b函数内的变量b,是作为上层a函数的AO对象的属性,名为b,值为function(){ console.log(b )}
调试工具如下:
以上例子没有形成闭包。由于b函数内部定义了变量b,打印时直接使用的是
3、闭包的保持
如果希望在函数调用后,闭包依然保持,就需要将内部函数返回到外部函数的外部。
function a() {
var num = 0
function b() {
console.log(num++)
}
return b
}
var demo = a()
console.dir(demo)
demo() // 0
demo() // 1
形成闭包且被保持住了。调用a函数的时候,将内部函数b返回,保存在函数a的外部。
可以利用断点查看Scope。这是在调用了a函数的dir:
// 闭包3
function fn1() {
var b1 = 1
var c1 = 2
// 这个函数就是个闭包,可以访问外层 a 函数的变量
return function() {
var d1 = 3
return b1 + c1 + d1
}
}
console.log(fn1()()) // 6
console.log(b1, c1, d1) // b1 is not defined
var test = (function(a) {
console.log('第二步执行', a) // 1
this.a = a
return function(b) {
console.log('调用后的第三步',b) // 4
return this.a + b
}
})(
(function(a, b) {
console.log('第一步执行', a, b) // 1,2
return a
})(1, 2)
)
console.log(test(4)) // 5
4、总结
使用闭包要满足两个条件:
① 闭包要形成:在内部函数使用外部函数的变量;
② 闭包要保持:内部函数返回到外部函数的外面;
5、闭包的两面性
① 优点
一般来说,在函数外部是无法访问函数内部的变量的,设计闭包最主要的作用就是为了解决这个问题,使得函数外部可以访问函数内部的变量。