前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端面试题JS闭包:7种解决办法

前端面试题JS闭包:7种解决办法

作者头像
疯狂的技术宅
发布2019-03-27 16:20:11
1.1K0
发布2019-03-27 16:20:11
举报
文章被收录于专栏:京程一灯京程一灯

问题:

什么是闭包?以下代码点击会输出什么?为什么?能大概说明白的话继续问能想出几种解决办法。

代码语言:javascript
复制
<!DOCTYPE HTML> 
<html> 
<head> 
<meta charset="utf-8" /> 
<title>闭包演示</title> 
<style type="text/css"> 
 p {background:gold;} 
</style> 
<script type="text/javascript"> 
function init() { 
 var pAry = document.getElementsByTagName("p"); 
 for( var i=0; i<pAry.length; i++ ) { 
 pAry[i].onclick = function() { 
 alert(i); 
 } 
 } 
} 
</script> 
</head> 
<body onload="init();"> 
<p>产品 0</p> 
<p>产品 1</p> 
<p>产品 2</p> 
<p>产品 3</p> 
<p>产品 4</p> 
</body> 
</html>

答案:弹出的结果都是5. 出错:获取HTML元素集合,循环给元素添加事件。在事件响应函数中(event handler)获取对应的索引。但每次获取的都是最后一次循环的索引。 出错原因:初学者并未理解JavaScript的闭包特性。通过element.onclick=function(){alert(i);}方式给元素添加点击事件。响应函数function(){alert(i);}中的 i 并非每次循环时对应的 i(如0,1,2,3,4)而是循环后最后 i 的值5。 或者说循环时响应函数内并未能保存对应的值 i,而是最后一次i++的值5。

解决方法:见html代码注释部分

代码语言:javascript
复制
<!DOCTYPE HTML> 
<html> 
<head> 
<meta charset="utf-8" /> 
<title>闭包演示</title> 
<style type="text/css"> 
 p {background:gold;} 
</style> 
<script type="text/javascript"> 
/* 网上的七种方法

//将变量 i 保存给在每个段落对象上
function init() { 
 var pAry = document.getElementsByTagName("p"); 
 for( var i=0; i<pAry.length; i++ ) { 
 pAry[i].i=i; 
 pAry[i].onclick = function() { 
 alert(this.i); 
 } 
 } 
}

//将变量i保存在匿名函数自身
function init(){
 var pAry=document.getElementsByTagName("p");
 for (var i = 0; i <pAry.length; i++) {
 (pAry[i].onclick=function(){
 alert(arguments.callee.i)
 }).i=i;
 };
} 


//加一层闭包,i以函数参数形式传递给内层函数
function init(){
 var pAry=document.getElementsByTagName("p");
 for (var i = 0; i < pAry.length; i++) {
 (function(arg){
 pAry[i].onclick=function(){
 alert(arg);
 };
 })(i);//调用时参数
 };
}


//加一层闭包,i 以局部变量形式传递给内层函数 
function init(){
 var pAry=document.getElementsByTagName("p");
 for (var i = 0; i < pAry.length; i++) {
 (function(){
 var temp=i;//调用时局部变量
 pAry[i].onclick=function(){
 alert(temp);
 }
 })();
 };
}



//加一层闭包,返回一个函数作为响应事件
function init(){
 var pAry=document.getElementsByTagName("p");
 for (var i = 0; i < pAry.length; i++) {
 pAry[i].onclick=function(arg){
 return function(){
 alert(arg);
 }
 }(i);
 };
}



function init(){
 var pAry=document.getElementsByTagName("p");
 for (var i = 0; i < pAry.length; i++) {
 pAry[i].onclick=new Function("alert("+i+");");//new一次就产生一个函数实例

 };
}

function init(){
 var pAry=document.getElementsByTagName("p");
 for (var i = 0; i < pAry.length; i++) {
 pAry[i].onclick=Function("alert("+i+");");

 };
}

*/
function init() { 
 var pAry = document.getElementsByTagName("p"); 
 for( var i=0; i<pAry.length; i++ ) { 
 pAry[i].onclick = function() { 
 alert(i); 
 } 
 } 
} 

</script> 
</head> 
<body onload="init();"> 
<p>产品 0</p> 
<p>产品 1</p> 
<p>产品 2</p> 
<p>产品 3</p> 
<p>产品 4</p> 
</body> 
</html>

往期精选文章

ES6中一些超级好用的内置方法

浅谈web自适应

使用Three.js制作酷炫无比的无穷隧道特效

一个治愈JavaScript疲劳的学习计划

全栈工程师技能大全

WEB前端性能优化常见方法

一小时内搭建一个全栈Web应用框架

干货:CSS 专业技巧

四步实现React页面过渡动画效果

让你分分钟理解 JavaScript 闭包


小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-09-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档