闭包指的是那些引用了另一个函数作用域中变量的函数
const obj = {
name:'obj.name',
sayName:function(){
const name = this.name;
return function(){
console.log(name);
}
}
}
obj.sayName()(); // obj.name
name 变量是在sayName方法中定义的,而sayName内部定义并返回的函数引用了这个变量,被返回的函数在其他地方使用后,仍然引用着那个变量,这个就是因为被返回的内部函数的作用域链包含着sayName方法的作用域,对于作用域不熟悉的读者可以去查阅一下相关文档。
在函数执行时,要从作用域链去寻找变量,自己没有就去外部找,一层一层,直到找到全局作用域都还没有时就返回undefined。
在函数执行时,每个执行上下文中都会有一个包含其中变量的对象。全局上下文中叫变量对象,它在代码执行期间始终存在,函数局部上下文中的叫活动对象,只在函数执行期间存在。
在一般情况下,函数执行完毕后,局部活动对象会被销毁,内存中就只剩下全局作用域。不过闭包就不一样了,在一个函数内部定义的函数会把其包含函数的活动对象添加到自己的作用域中,而当我们把内部函数返回出去时,一个闭包就已经形成了,如果我们声明一个变量去接收它,那么被返回的函数就始终有个东西去指向它,从而导致该函数的活动对象无法被销毁,外部函数虽然执行上下文的作用域链被销毁了,但其活动对象仍然会保留在内存中,直到被返回的函数失去指向它的东西被销毁后,该活动对象才被销毁。
闭包的作用
- 保护:划分一个独立的代码执行区域,在这个区域中有自己私有变量存储的空间,而用到的私有变量和其它区域中的变量不会有任何的冲突(防止全局变量污染)
- 保存:如果上下文不被销毁,那么存储的私有变量的值也不会被销毁,可以被其下级上下文中调取使用(延伸变量的作用范围)
闭包危害
内存泄漏:闭包产生的变量都会常驻在内存中,对内存的消耗非常大,如果滥用闭包,会造成内存泄漏,降低网页的性能;
function bindEvent() {
let ele = document.querySelector('.ele');
ele.onclick = function () {
console.log(ele.style.color);
};
};
bindEvent();
/*
由于点击事件中使用到了外层函数中的DOM ele,导致 ele 始终无法释放
大家都知道操作DOM本来是件不太友好的事情,你现在操作别人不说,还抓着不放了,你良心不会痛?
*/
在函数的内部再去创建一层函数,其实是不好的做法,善用this,尽量不使用闭包