面试必答之作用域链与闭包
闭包有多重要?如果你是初入前端的朋友,我没有办法直观的告诉你闭包在实际开发中的无处不在,但是我可以告诉你,前端面试,必问闭包。面试官们常常用对闭包的了解程度来判定面试者的基础水平,保守估计,10个前端面试者,至少5个都死在闭包上。
作用域链【主要作用:变量名解析】
如果你理解了作用域链,那么闭包对于你而言,理解起来就相当地简单了。
作用域链,当然可以看成是一个(有序检索)的对象列表。
有序检索:即就近原则“由近及远”,全所以大家一定要明白局对象始终是最后一个!
举例来说,也就是:
假如JS的顶级代码(不包含在函数内的代码),它的作用域链就是一个全局对象;
假如JS代码中有函数,但是没嵌套,它的作用域链有两个对象,第一个是函数内的变量即函数参数,第二个就是全局对象【第一第二的顺序很重要】;
假如有函数嵌套,那么作用域链至少有3个对象。
了解完作用域链的主要作用,这个时候我们就要知道它的【创建规则】
定义函数的时候,会保存一个作用域链;
调用函数的时候,有两个操作:一是将函数内的局部变量保存在一个新建对象中,然后添加到函数定义时的作用域链中;二是会创建一个“运行期上下文”的内部对象,每一个运行期上下文都有一个单独的作用域链,而调用时会将上面提到那个作用域链中的对象相当于复制一份到运行期上下文这个作用域链中。
在嵌套函数时,有些不一样,我们每一次调用外部函数的时候,内部函数都需要重新定义一次,因为每次运行外部函数时,它的作用域链都是不相同的。内部函数在每次定义时也有微妙的差别——在每次调用外部函数的时候,内部函数的代码是相同的,而且关联这段代码的作用域链也不相同。
function buttonInit(){
for(var i=1;i<4;i++){
var b=document.getElementById("button"+i);
b.addEventListener("click",function(){
alert("Button"+i); },false);
}
}
window.onload=buttonInit;
//--结果:都是button4
function buttonInit(){
for(var i=1;i<4;i++){
(function a(j) {
console.log(j);
var b=document.getElementById("button"+j);
b.addEventListener("click",function(){
alert("Button"+j);
},false);
})(i)
}
}
window.onload=buttonInit;
//--结果:button1、button2、button3
闭包:【主要作用:变量私有化】
缺点:
1、 闭包会让函数内部变量始终保存在内存中,需要手动释放资源;
【解决办法:即将函数设置为null】
2、过多的闭包导致内存泄漏。
实现闭包:
当嵌套函数被作为外部函数的返回值返回或者存储在某处的属性里,这时会有一个外部引用指向这个嵌套函数,就不会被回收,并且这个嵌套函数所指向的变量绑定对象也不会回收。
function buttonInit(){
for(var i=1;i<4;i++){
var b=document.getElementById("button"+i);
b.addEventListener("click",function(){
alert("Button"+i); },false);
}
}
window.onload=buttonInit;
//--结果:都是button4
function buttonInit(){
for(var i=1;i<4;i++){
(function a(j) {
console.log(j);
var b=document.getElementById("button"+j);
b.addEventListener("click",function(){
alert("Button"+j);
},false);
})(i)
}
}
window.onload=buttonInit;
//--结果:button1、button2、button3
本次给大家推荐一个最后给大家推荐一个免费的学习群,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
对web开发技术感兴趣的同学,欢迎加入Q群:864305860,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。
最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。