for循环闭包引发的思考

文章导航

×
  1. 1. 将变量 i 保存给在每个对象(li)上
  2. 2. setAttribute getAttribute
  3. 3. return function IIFE 传参
  4. 4. 将变量 i 保存在匿名函数自身
  5. 5. 加一层闭包,i以局部变量形式传递给内存函数
  6. 6. 用Function实现,实际上每产生一个函数实例就会产生一个闭包
  7. 7. 用Function实现 不new
  8. 8. bind
  9. 9. 函数调用
  10. 10. 函数调用和bind配合
  11. 11. 事件委托
  12. 12. es6

闭包是指可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)
最常用的场景是筛选一组同元素节点给每个元素加上点击事件来弹出各自index索引(回调函数操作)for循环闭包引发的思考demo

1
2
3
4
5
6
7
<ul class="list" id="list">
<li data-value="360" class="active">360</li>
<li data-value="qq">qq</li>
<li data-value="ly">ly</li>
<li data-value="xiaomi">xiaomi</li>
<li data-value="huawei">huawei</li>
</ul>
1
2
3
4
5
6
7
8
9
10
/* 都弹出5 闭包问题 正确的是希望弹出0,1,2,3,4 */
function closure() {
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].onclick = function() {
alert(i);
}
}
}
closure()

如下是解决闭包的方法12种

for循环闭包引发的思考

将变量 i 保存给在每个对象(li)上

1
2
3
4
5
6
7
8
9
10
function closure1() {     
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].i=i;
aLis[i].onclick = function() {
alert(this.i);
}
}
}
closure1()

setAttribute getAttribute

1
2
3
4
5
6
7
8
9
10
function closure2() {     
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].setAttribute("index",i);
aLis[i].onclick = function() {
alert(this.getAttribute("index"));
}
}
}
closure2()

return function IIFE 传参

1
2
3
4
5
6
7
8
9
10
11
function closure3() {     
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].onclick=(function(x){
return function(){
alert(x)
}
})(i)
}
}
closure3()

将变量 i 保存在匿名函数自身

1
2
3
4
5
6
7
8
9
function closure4() {     
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
(aLis[i].onclick = function() {
alert(arguments.callee.i);
}).i = i;
}
}
closure4()

加一层闭包,i以局部变量形式传递给内存函数

1
2
3
4
5
6
7
8
9
10
11
12
function closure5() {     
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
(function () {
var temp = i;//调用时局部变量
aLis[i].onclick = function() {
alert(temp);
}
})();
}
}
closure5()

用Function实现,实际上每产生一个函数实例就会产生一个闭包

1
2
3
4
5
6
7
function closure6() {     
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].onclick = new Function("alert(" + i + ");");//new一次就产生一个函数实例
}
}
closure6()

用Function实现 不new

1
2
3
4
5
6
7
function closure7() {     
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].onclick = Function('alert('+i+')')
}
}
closure7()

bind

1
2
3
4
5
6
7
8
9
function closure8() {     
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].addEventListener('click',function(i){
alert(i)
}.bind(this,i))
}
}
closure8()

函数调用

1
2
3
4
5
6
7
8
9
10
11
12
function say(index){
return function(){
alert(index)
}
}
function closure9() {
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].onclick = say(i)
}
}
closure9()

函数调用和bind配合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//兼容ie8 不支持bind
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
function say(index){
alert(index)
}
function closure10() {
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].onclick = say.bind(aLis[i],i)
}
}

closure10();

事件委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 var addEvent = function(element,type,callback){
if(element.addEventListener){
element.addEventListener(type,callback,false);
}else if(element.attachEvent){
element.attachEvent('on' + type,callback)
}

}
function closure11() {
var oListDom = document.getElementById("list");
var aLis = oListDom.getElementsByTagName("li");
/* way1 */

oListDom.addEventListener("click",function(e){
var e = e || window.event;
var target = e.target || e.srcElemnt;
for( var i=0; i<aLis.length; i++ ) {
if(aLis[i]==target){
alert(i)
}
}
})


/* way2 兼容处理 */

addEvent(oListDom,"click",function(e){
var e = e || window.event;
var target = e.target || e.srcElement;
for( var i=0; i<aLis.length; i++ ) {
if(aLis[i]==target){
alert(i)
}
}
})

}

closure11()

es6

1
2
3
4
5
6
7
8
9
10
11
function closure12() {  
"use strict";
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
let j = i;//创建一个块级变量
aLis[i].onclick = function(){
alert(j)
}
}
}
closure12()

ps:目前就总结这么多,遇到了新的会添加上


版权声明: 本文章采用 知识共享署名 2.5 中国大陆许可协议 进行许可,欢迎转载,但转载请注明来自李立冬博客,并保持转载后文章内容的完整。本人保留所有版权相关权利。
本文链接:http://www.lilidong.cn/2017/04/06/for循环闭包引发的思考/

分享到: 更多