简体   繁体   中英

Javascript: Iterate/loop through multiple axes/directions?

As you'll see below, I'm trying to write some logic that has to be repeated twice - once for the horizontal direction, and a second time for the vertical direction. The problem is that each direction has different function names and it's not like other scenarios where you can iterate via integers. Is there a more elegant way to rewrite it?

// 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
});

Here's a way I've managed to do it, but while the code duplication is eliminated, I feel like it's incredibly confusing and hardly maintainable.

// 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
  });
}

Any ideas?

Also, I wasn't sure what to call the question. Is there a better terminology to describe what I'm trying to do here?

In general, your approach was fine. However your code has the infamous Loop issue - all installed event handlers will use the variable values from the last iteration.

You should use an array literal instead of an object literal, which also has the advantage that you don't need the loopParams variable and the explicit for -loop when you can just use forEach - getting the closure for free.

[
  {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
  });
});

Of course you may use more succint variable & property names.

You do need to weight the benefits of eleminating duplication against the added complexity. For only two similar functions (if they're really as short as in your question) with so many (4) different pieces the advantage gained does not seem large enough to make this rewrite necessary.


Other techniques that could be applied here are a) the closure factory - removing the need for a parameter object:

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');

or b) just using different handlers, and outsourcing the common functionality in external functions:

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]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM