闭包是属于比较高级的 js 变成范畴,最近在重新学习 JS 基础知识,尝试解释一下闭包。

概念

闭包函数:声明在一个函数中的函数,叫做闭包函数。
像这样:

1
2
3
4
5
6
function parentFn(){
return sonFn(){
console.log(111)
}
}
parentFn()() // 111

一个知识点:只有使用 () 函数才会执行。

闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

这里所谓的寿命终结是指,当函数执行完成以后将会被内存回收机制收回。这里收回的也是函数在执行时开辟的私有作用域。

像这样:

1
2
3
4
5
6
function parentFn(){
var num = 1;
return sonFn(){
return num
}
}

为什么会产生闭包

JS 本身为了避免解释器过量消耗内存,造成系统崩溃, 自带有一套垃圾回收机制,垃圾回收机制能够检测到一个 对象是不是无用 的。检测到之后,就会把它占用的内存释放掉。但是实际工作中,我们也会需要一些变量不那么及时的被清理,所以就出现了闭包,用来达成这个效果。

另外,声明一个函数在全局形成了一个私有的作用域,所以我们有时候需要操作函数内(作用域)的变量就需要通过闭包来实现访问和修改的功能。

注意看重点,对象是不是无用的,那么怎样就无用呢??上面有一部分解释,函数执行完以后即被回收,我们来看下面的例子。

1
2
3
4
5
6
7
8
9
var add = (function{
var num = 1;
return sonFn(){
return num ++
}
})()

add() // 1
add() // 2

解释一下,自执行匿名函数被执行了,所以要销毁,但是它内部的一个变 numsonFn 所使用,sonFn 还没有执行,所以导致 num 不会被释放,我们知道函数对象和普通对象的区别就是不能缓存变量,这个例子因为内部引用所以不会被回收,所以导致这个 num 一直存在。

闭包能干什么

一直信奉一点,技术是为了解决问题而存在的,所以用技术来解决实际的问题,的才是技术存在的意义。

1. 作为私有空间,防止变量污染,有助于模块化代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var foo = (function(){
var secret = 'secret';// “闭包”内的函数可以访问 secret 变量,而 secret 变量对于外部却是隐藏的
return{
get_secret: function(){ // 通过定义的接口来访问 secret
return secret;
},
new_secret: function(new_secret){ // 通过定义的接口来修改 secret
secret = new_secret;
}
};
}());

foo.get_secret(); // 得到 'secret'
foo.secret; // Type error,不能访问
foo.new_secret('a new secret'); // 通过函数接口,我们访问并修改了 secret 变量
foo.get_secret(); // 得到 'a new secret'

2. 缓存变量值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

function add() {
var counter = 0;
return counter += 1;
}

add();
add();
add();

// 计数器每次都是 1,函数执行一次既销毁。
// 使用闭包

function add() {
var counter = 0;
return function(){
return counter += 1;
}
}
var sum = add()

sum() // 1
sum() // 2
sum() // 3

// 补充,sum是一个非纯函数