问题起源
一个函数执行后,内部的变量会被回收(销毁),有没有一种办法能让这个变量继续存在呢?
几个名词
Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。
变量回收是指在一些编程语言中,函数内的局部变量只在函数执行期间存活。
一旦 makeFunc() 函数执行完毕,你可能觉得 name 变量就不能存在了。闭包的最大特性就是,如果里函数引用了父级函数的某个变量,那这个变量就能享受和全局变量一样的特权,不会被回收!除非你关闭页面或浏览器!
function makeFunc() {
var name = 'Mozilla';
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
闭包原理
-
闭包是由函数以及该函数的词法环境组合而成,这个环境包含了这个闭包创建时所能访问的所有局部变量
-
returen一个函数,再把这个函数当做回调函数赋给事件(事件执行时才真正触发)
-
变量可以是父级函数的属性,也可以是父级函数所接受的参数
-
两大作用:读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中
-
同一个闭包机制可以创建多个闭包函数出来,它们彼此没有联系,都是独立的,并且每个闭包函数可以保存自己个性化的信息。
-
以下三个闭包彼此独立、没有联系:
function f1(num){
function f2(){
alert('数字:'+num);
}
return f2;
}
var fa = f1(10);
var fb = f1(20);
var fc = f1(30);
fa(); //数字:10
fb(); //数字:20
fc(); //数字:30
MDN的例子
这个例子是通过点击三个按钮来动态的改变网页文本的大小,不过这个例子有点鸡肋,有种为了写闭包而刻意写成这样的感觉。
<body>
<p>Some paragraph text</p>
<h1>some heading 1 text</h1>
<a href="#" id="size-12">12</a>
<a href="#" id="size-16">16</a>
// onclick在html中只能用 func()的形式
<button id="button" onclick="test(5)">点击</button>
<script>
function makeSizer(size) {
return function() {
document.body.style.fontSize = size + 'px';
};
}
var size12 = makeSizer(16);
var size16 = makeSizer(24);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-16').onclick = size16;
function test(x){
console.log('我是' + x )
}
// onclick在js代码中只能传入事件名func,在html中只能用 func()的形式
// document.getElementById('button').onclick = test;
</script>
</body>
一个常见问题
for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i)//10个10
},1000)
}
解决办法:
- 用let替换var,三个环境和一个环境
- 匿名函数
用匿名函数包裹原函数后形成了一个闭包,这保证了 每个 i 在当时块级作用域中的环境被保存下来,所以每次输出都不同
for (var i = 0; i < helpText.length; i++) {
(function() {
var item = helpText[i];
document.getElementById(item.id).onfocus = function() {
showHelp(item.help);
}
})(); // 立即调用绑定函数,使用正确的值绑定到事件上;而不是使用循环结束的值
}
注意
闭包带来的性能问题,过多的使用闭包会导致占用内存太多
参考:
https://developer.mozilla.org/zhCN/docs/Web/JavaScript/Closures
https://blog.csdn.net/coder_vader/article/details/78839686
https://juejin.im/entry/58f424d5570c3500563d7541
https://zhuanlan.zhihu.com/p/22486908