下面这个ul,如何点击每一列的时候alert其index,请写出非闭包和闭包实现js代码。
<ul id='test'><li>第一条</li><li>第二条</li><li>第三条</li></ul>
非闭包
// 方法一:
var test=document.getElementById('test')
var testList=document.getElementsByTagName('li')
// 给每个li增加一个index
// 再给每个li元素添加一个click事件
for(var i=0;i<testList.length;i++){
testList[i].index=i
testList[i].addEventListener('click',function(){
alert(this.index)
})
}
数据量大的情况下,方法一的性能没那么好,是因为:
在js中,添加到页面上的事件处理程序的数量将直接关系到页面的整体运行性能,
因为需要不断地与dom节点进行交互,访问dom的次数越多,引起浏览器的重绘与重排的次数就会越多
,那么就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是 减少dom操作的原因。
我们就会用到事件委托的方式去进行处理
如果用事件委托的方式,就会将所有的操作放在js程序里面,与dom的操作就只有交互一次,这样就能大大地减少与dom的交互次数,提高性能;
每个函数都是一个对象,是对象就会占用内存,对象越多,内存的占用率就会越大,自然性能就越差了。
事件委托的原理
–事件的冒泡原理,就是事件从最深的节点开始,然后逐步向上传播事件
举个栗子🌰
,页面上有一个节点数,div>ul>li>button,比如我们给最里面的button添加一个click点击事件,那么这个事件就会一层一层地往外执行,执行顺序button>li>ui>div,有这样的一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,button做点击之前的时候,都会冒泡到最外层的div,所以都会触发,这就是事件的委托,委托它们父级代为执行的事件
//非闭包-事件委托 方法二
var test=document.getElementById('test')
var testList=document.getElementsByTagName('li')
test.onclick=function(event){
var event=event || window.event
var target=event.target || event.srcElement;
for(var i=0;i<testList.length;i++){
testList[i].index=i
}
// nodeName是大写,要把它转成小写
if(target.nodeName.toLowerCase()==='li'){
alert(target.index)
}
}
闭包
大家可以先试试下面的代码alert出来的
var test=document.getElementById('test')
var testList=document.getElementsByTagName('li')
for(var i=0;i<testList.length;i++){
testList[i].onclick=function(){
alert(i)
}
}
//点击每一个li的时候,alert出来的都是3 is wrong
其实上面的与
js的事件循环机制有关
,当我们给元素绑定事件的时候,就会形成异步,又因为js是单线程语言(一次只会执行一件事情),上面的这段代码开始执行后,会读取到for循环(声明并初始化i的值,对i的值进行判断),然后进入for循环体内(本身是同步执行的),遇到异步函数,异步函数会加入到事件队列当中,所有的异步函数都在这里,等其他同步的函数被执行完了之后,才会被立刻执行,知道i的值,不再满足for循环的执行条件,便开始执行事件队列当中的异步事件。
so we should use 闭包to对付他
//方法一:
var test=document.getElementById('test')
var testList=document.getElementsByTagName('li')
for(var i=0;i<testList.length;i++){
(function(i){
testList[i].onclick=function(){
alert(i)
}
})(i)
}
//方法二 --赋值给局部变量
var test=document.getElementById('test')
var testList=document.getElementsByTagName('li')
for(var i=0;i<testList.length;i++){
(function(){
var j=i
testList[i].onclick=function(){
alert(j)
}
})()
}
//方法三 --返回一个函数作为响应事件
var test=document.getElementById('test')
var testList=document.getElementsByTagName('li')
for(var i=0;i<testList.length;i++){
testList[i].onclick = (function (arg) {
return function () {
alert(arg);
};
})(i);
}