闭包是指可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)
最常用的场景是筛选一组同元素节点给每个元素加上点击事件来弹出各自index索引(回调函数操作)
<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>
/* 都弹出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种
将变量 i 保存给在每个对象(li)上
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
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 传参
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 保存在匿名函数自身
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以局部变量形式传递给内存函数
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实现,实际上每产生一个函数实例就会产生一个闭包
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
function closure7() {
var aLis = document.getElementsByTagName("li");
for( var i=0; i<aLis.length; i++ ) {
aLis[i].onclick = Function('alert('+i+')')
}
}
closure7()
bind
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()
函数调用
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配合
//兼容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();
事件委托
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
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()
深圳 · 龙岗 · 大运软件小镇22栋201
电话:400 182 8580
邮箱:szhulian@qq.com