Javascript:迭代/循环多个轴/方向?

时间:2014-08-07 20:06:53

标签: javascript loops refactoring

正如您将在下面看到的那样,我试图编写一些必须重复两次的逻辑 - 一次用于水平方向,另一次用于垂直方向。问题是每个方向都有不同的函数名称,并且它与其他可以通过整数迭代的场景不同。是否有更优雅的方式来重写它?

// Some calculations along the horizontal axis
someElementX.addEventListener('some-event', function(e){
  var someResult = e.clientX - thisElement.style.left;
  var someOtherResult = e.clientY; // Also some quick orthogonal calculation
});

// Some calculations along the vertical axis
someElementY.addEventListener('some-event', function(e){
  var someResult = e.clientY - thisElement.style.top;
  var someOtherResult = e.clientX; // Also some quick orthogonal calculation
});

这是我设法做到的一种方式,但是当代码重复被删除时,我觉得它令人难以置信的混乱,难以维护。

// Set up a "direction" loop
var loopParams =
  { 0: { xy: 'x', clientXY: { 1: 'clientX', 2: 'clientY' }, side: 'left' } 
  , 1: { xy: 'y', clientXY: { 1: 'clientY', 2: 'clientX' }, side: 'top'  }
  };

// Run the loop for each direction
for( var i = 0; i < 2; i++ )
{
  var xy       = loopParams[i].xy;
  var clientXY = loopParams[i].clientXY;
  var side     = loopParams[i].side;

  someElements[xy].addEventListener('some-event', function(e){
    var someResult      = e[clientXY[1]] - thisElement.style[side];
    var someOtherResult = e[clientXY[2]]; // Some quick orthogonal calculation
  });
}

有什么想法吗?

另外,我不确定该怎么称呼这个问题。有没有更好的术语来描述我在这里尝试做什么?

1 个答案:

答案 0 :(得分:2)

总的来说,你的方法很好。但是,您的代码具有infamous Loop issue - 所有已安装的事件处理程序将使用上次迭代中的变量值。

您应该使用数组文字而不是对象文字,这样做的好处还在于您不需要loopParams变量和显式for - 循环当你可以使用forEach - 免费获得关闭时。

[
  {dir:'x', posProp:'clientX', otherProp:'clientY', side:'left'},
  {dir:'y', posProp:'clientY', otherProp:'clientX', side:'top'}
].forEach(function(loopParam) {
  someElements[loopParam.dir].addEventListener('some-event', function(e){
    var someResult      = e[loopParam.posProp] - thisElement.style[loopParam.side];
    var someOtherResult = e[loopParam.otherProp]; // Some quick orthogonal calculation
  });
});

当然你可以使用更多的succint变量&amp;财产名称。

您确实需要在增加复杂性的同时减轻重复使用的好处。对于只有两个相似的功能(如果它们真的像你的问题一样短),有这么多(4)个不同的部分,所获得的优势似乎不足以使这种重写成为必要。


这里可以应用的其他技术是:a)闭包工厂 - 不需要参数对象:

function addXYHandler(el, posProp, otherProp, side) {
  el.addEventListener('some-event', function(e){
    var someResult      = e[posProp] - thisElement.style[side];
    var someOtherResult = e[otherProp]; // Some quick orthogonal calculation
    // much "duplicate" code
  });
}
addXYHandler(someElementX, 'clientX', 'clientY', 'left');
addXYHandler(someElementY, 'clientY', 'clientX', 'top');

或b)仅使用不同的处理程序,并将外部函数中的常用功能外包出去:

function someResult(…) { … }
function someOtherResult(…) { … }
// or maybe use only one function with multiple parameters
var handlers = {
  x: function(e) {
    someResult(e.clientX - thisElement.style.left);
    someOtherResult(e.clientY);
  },
  y: function(e){
    someResult(e.clientY - thisElement.style.top);
    someOtherResult(e.clientX);
  }
});
for (var dir in handlers)
  someElements[xy].addEventListener('some-event', handlers[dir]);