闭包
- 有权访问另一个函数作用域中的变量的函数
- 函数 A 内部有函数 B, B 可以访问到函数 A 变量,那么函数 B 就是闭包
存储在堆中
产生闭包
js
function fn() {
var mty = 10;
return function () {
return mty;
};
}
作用
- 延续局部变量寿命、封装变量
应用场景
访问私有方法和变量
return 返回函数:无网、音量检测:调用之后,返回销毁方法、无网、音量
柯里化: 函数可以分多次调用,从而得到结果,设置私有变量
bind:暂存 this context
自执行函数:for 循环里面有异步操作,异步操作需要用到 index
上报:
js
// report 函数调用结束后, img 随即被销毁,或许还没来得及发送 http 请求
var report = function (src) {
var img = new Image();
img.src = src;
};
report("http://xxx.com/getUserInfo");
// 改造后
var sendLog = (funtion(){
var img = [];
return (src) => {
var img = new Image();
imgs.push(img);
img.src = src;
};
})();
- 封装变量:for 循环里面有异步操作,异步操作需要用到 index
js
for (var i = 0; i < 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
}, 0);
})(i);
}
document.getElementById
js
var getId = function (id) {
return document.getElementById(id);
};
getId("div1");
我们也许思考过为什么不能用下面这种更简单的方式: var getId = document.getElementById; getId( 'div1' );
这是因为许多引擎的 document.getElementById 方法的内部实现中需要用到 this。这个 this 本来被期望指向 document,当 getElementById 方法作为 document 对象的属性被调用时,方法内部的 this 确实是指 向 document 的。
但当用 getId 来引用 document.getElementById 之后,再调用 getId,此时就成了普通函数调用, 函数内部的 this 指向了 window,而不是原来的 document。
js
document.getElementById = (function (func) {
return function () {
return func.apply(document, arguments);
};
})(document.getElementById);
var getId = document.getElementById;
var div = getId("div1");
缺点
- 使用不当容易造成内存泄露
内存泄露
闭包,未用到变量未及时释放
定时器未释放
dom 引用:dom 删除时,引用未解除
意外全局变量
监听事件:未正确销毁
dom 删除引用未解除
js
// 拿到待删除节点:
var self = document.getElementById("to-be-removed");
// 拿到父节点:
var parent = self.parentElement;
// 删除:
var removed = parent.removeChild(self);
removed === self; // true
为什么不创建一个全局变量来代替这个局部变量?
- 因为全局变量会被污染或者被修改。
- 闭包能够访问里面的变量,是由于作用域链,用到了函数嵌套中,内部函数能够访问父级函数作用域的变量这个理念。