这两个for循环可以简化吗?

可以合并吗

for(i=0;i<oBtn1.length;i++){
      oBtn1[i].onclick=function(){
          alert('a');
      }
}
for(i=0;i<oSp1.length;i++){
      oSp1[i].onclick=function(){
          alert('a');
      }
}
阅读 4.7k
9 个回答

别人问的是可不可以合并,楼上一大坨说的啥,好像恨不得把几十年学的js全抖出来,万一楼主有不可告人的原因而无法使用dom123456789级还有代理呢?

var len = Math.max(oBtn1.length,oSp1.length)
for(i=0;i<len;i++){
    if(oBtn1[i]){
        oBtn1[i].onclick=function(){
           alert('a');
        }
    }
    if(oSp1[i]){
       oSp1[i].onclick=function(){
          alert('a');
      }
    }
      
}

看你们这么个回答,我。。。想知道题主想问的是啥?给列表添加点击事件?
那就用事件委托,在列表外层的ul或div上添加点击吧

document.getElementById('container').addEventListener('click', function(event) {
    var target = event.target;
    if(target.tagName == 'li'){
        alert(target.innerText);
    }
}, false);

ps:
真热闹。。。多交流挺好的哈哈?
你们在讲dom0级事件让我想到了React的合成事件的底层。他用的也是事件委托哦。

1.首先,这是dom 0级的事件。现在已经不推荐这样注册了
2.对于多个dom元素需要注册同类型的事件的情况,可以给他们的父元素注册事件,在冒泡过程中对子元素的事件进行处理

用delegate模式啊。http://api.jquery.com/on/

$( "#dataTable tbody" ).on( "click", "tr", function() {
  console.log( $( this ).text() );
});

从代码中初步断定为楼主循环目的为多元素绑定事件并且采用的是DOM 0级事件绑定方式,我这边先对1楼说的不推荐事件这么注册补充一些说明,然后在针对代码简化提一些建议。

首先,0级的事件绑定一大优势就在于有着较好的向后兼容性,因为最早标准没出来的时候主流浏览器厂商做的事件绑定都这么绑,标准出来后之后总得兼顾以前的代码吧,因此这种绑定方式也被留了下来。这种绑定方式的最大缺点在于无法为同一个元素同一个事件绑定多个处理函数,而且通过w3c事件绑定即x.addEventListener能指定事件的处理阶段是在捕获阶段还是在冒泡阶段。综上所述,因为0级事件存在无法对事件触发阶段进行更精细的控制并且不在w3c标准内,因此在使用上要加以斟酌。

针对代码部分,我理解为楼主合并两个循环的目的为简化代码量并提升性能,在提升算法性能思路上可以考虑将两个循环合并为一个循环,当oBtn1的集合长度与oSp1的长度相等时,此时单层循环就能解决合并问题。

// 我不知道楼主这边查询到的DOM节点集合是nodeList还是什么类型
// 如果是nodeList类型集合会存在与DOM树实时同步的特点,建议遍历时
// 把长度值先另存下来
for(let i=0, len = oBtn1.length; i<len;i++){
  oBtn1[i].onclick = function(){
  alert('a');
}

oSp1[i].onclick = function(){
  alert('b');
}

}

当两集合长度不一样的时,一层循环的一个思路在于使用较长的那个长度作为遍历次数,
在内部根据当前长度值判断为哪个元素进行事件绑定。

let lenOfoBtn = oBtns.length;
let lenOfoSp1 = oSp1.length;
let len = Math.max(lenOfBtn, lenOfoSp1);
// 假设是Sp1长度比较短
for(let i=0; i<len;i++){
 oBtn1[i].onclick = function(){
 alert('a');
}

 if( i < lenBtnOfSp1 ){
   oSp1[i].onclick = function(){
      alert('b');
    }
 }
}

鉴于个人算法功底较差,此时如果想再一步优化算法性能,个人暂时没有可行的思路,或许能递归?

当然,在DOM中当然还能使用一楼提出的事件委托进行代码及性能层面上的优化。

// 伪代码
parentOfObtn = Obtn.parentNode;
parentOfoSp1 = oSp1.parentNode
parentOfbtn.addEventListener("click", function( e ){
// 识别事件触发对象是谁的条件语句,可能用类名或其他标识
if( e.target == xxx ){
  alert("a")
}
}, false)
parentOfoSp1 .addEventListener("click", function( e ){
// 识别事件触发对象是谁的条件语句,可能用类名或其他标识
if( e.target == xxx ){
  alert("b")
}
}, false)

更一步就是把事件委托到sp1与oBtn共有的祖先节点上,小透明第一次答题,
希望能对你有帮助。

楼上的回答已经说明怎么做了,但是还是要知道下为什么这样做,如下:
一般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们有100个li,每个li都有相同的click点击事件,可能我们会用for循环的方法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?
在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;
每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了(内存不够用,是硬伤,哈哈),比如上面的100个li,就要占用100个内存空间,如果是1000个,10000个呢,那只能说呵呵了,如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象进行操作,这样我们就需要一个内存空间就够了,是不是省了很多,自然性能就会更好。

还有另一种方式「合并」

function bindF(a) {
  for (var i = 0; i < a.length; ++i) {
    a[i].onclick = function () {
      alert('a');
    };
  }
}

bindF(oBtn1, i);
bindF(oSp1, i);


你知道 loop fusion 吗

题主的两个循环相互之间没有依赖关系

如果循环次数一样,是可以合成一个的

即便循环次数不一样

也可以强行合并(虽然理论上会被编译器再用 loop fission 拆成两个循环)

const { max } = Math;

var n = max(oBtn1.length, oSp1.length);
var i = 0;

function set(a, i) {
  if (i < a.length) {
    a[i].onclick = function () {
      alert('a');
    };
  }
}

for (; i < n; ++i) {
  set(oBtn1, i);
  set(oSp1, i);
}
var clickFunc = function(){
    alert('a');
};
for(i=0;i<oBtn1.length;i++){
      oBtn1[i].onclick=clickFunc;
}
for(i=0;i<oSp1.length;i++){
      oSp1[i].onclick=clickFunc;
}

为什么不用事件代理?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题