浅谈JS匿名函数和闭包

匿名函数

函数对于写过代码的大家来说怕是熟得不能再熟了。来个普普通通的函数先:

1
2
3
function add(a, b) {
return a + b;
}

这函数是普通了点,它的功能也无非是返回两个数的和。

那匿名函数呢,又是什么?
其实说白了就是没有名字的函数,像这个样子:

1
2
3
function () {
console.log("8080");
}

这写法有点新奇~,估计不少同学没试过这样来写函数吧,是的,它除了报错之外不会带来其他效果。首先它不能运行,就算能运行它也不能被调用,因为没有名字。
那有什么办法让它起作用呢?很简单,给它加个括号就行:

1
2
3
(function () {
console.log("8080");
})

加上括号之后,你会发现,报错不见了。嗯目前它已经是一个匿名函数的样子了,只要你在最后那里加上(),它立马就能运行起来:

1
2
3
(function () {
consol.log(8080);
})()

既然知道怎么用匿名函数了,接下来就探讨一下它和普通函数的区别吧。
我们知道,有没有名字对于程序来说有着重大意义。如果写一个无名函数,我们不用发愁怎么给它起名字,更不用担心会不会出现命名冲突了。还顺道解决了全局污染的问题。
哇~,听起来匿名函数是个好东西。嗯的确是这样,写代码的日常中,我们可以用匿名函数来运行一段小程序,还能用它来分割代码块,实现局部代码各不干扰的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ---代码块 1
(function () {
var a = 1,
b = 2;
// ...do something
console.log('start');
})(); // 小心不要漏写了这里的分号";"

// ---代码块 2
(function () {
var a = 1, //不会与之前的变量冲突
b = 2;
// ...do something
console.log('during');
})();

// ---代码块 3
(function () {
var a = 1, //不会与之前的变量冲突
b = 2;
// ...do something
console.log('ending');
})();

匿名函数还有更多新奇的作用,这里就不一一详述了~

闭包

接下来讲讲闭包,lz是个小学生,也曾走遍百度的每个角落寻找闭包的真正内涵,奈何度娘她动不动就给我一段文言文,像这样:

1
所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分

不知道大家看不看的懂,反正我是一脸懵13,最后自己参考和总结了下,大概是悟出了能够说服我自己的这么一个说法:
所谓闭包:就是函数的函数,

1
2
3
4
5
6
function func () {
var a = "2333";
return function () {
return a;
}
}

结果好像真的是这样,闭包就是这么回事而已(不过要注意,最后这个函数被外面的函数返回出去了,这样才能算是合格的闭包)。
很有趣的一点是,通过闭包,可以把局部变量驻留在内存中(避免了全局变量),举个例子,我们想实现变量的累加,一个简单的做法是把变量做成全局的,
这样大家都能访问到,累加就不是难事:

1
2
3
4
5
6
7
8
9
10
var count = 10;     //count是全局变量
function plus() { // 累加函数
count ++;
}
plus(); //调用累加->11
console.log(count);

plus(); //再累加 ->12
console.log(count);
// ...

但全局变量是个危险品,换成局部变量又实现不了累加

1
2
3
4
5
6
7
8
9
10
11
function plus() {   // 累加函数
var count = 10; //count是局部变量
count ++;
return count;
}
plus(); //累加 ->11
console.log(count);

plus(); //累加失败 还是 ->11
console.log(count);
// ...

遇到这种情况,就是闭包的发挥用处的时候啦:

1
2
3
4
5
6
7
function plus () {      // plus是个闭包
var count = 10;
return function () {
count++;
return count;
}
}

不过调用的时候要小心,如果是直接向下面这样调用的话是起不到效果的,因为变量被不断地初始化了:

1
2
3
4
5
6
7
8
9
10
11
12
function plus () {      // plus是个闭包
var count = 10;
return function () {
count++;
return count;
}
}
// ----错误的调用方式---
console.log(plus()()); //初始化count并累加
console.log(plus()()); //再度初始化count并累加
console.log(plus()()); // ...
console.log(plus()()); // ...

应该先把plus函数用临时变量存起来

1
2
3
4
5
6
// ----正确的调用方式---
var closure = plus ();
console.log(plus()());
console.log(plus()());
console.log(plus()());
console.log(plus()());

这样的话就实现累加了。
PS(这也是我后来才知道的真相):由于闭包里作用域返回的局部变量资源不会立即被销毁回收,所以会占用内存,过多使用会导致性能下降,建议在有必要的时候才使用它。
嗯就这么多了,以上是分享的内容,更多关于闭包的神奇用处也欢迎大家留言探讨~。