2

Not sure how to explain this. I'll try it with an example.

For example, I use the following function as a short for a for loop over an array:

function forEach(array, f) {
  var len = array.length, i;
  for (i = 0; i < len; i += 1) {
    f(i, array[i], len);
  }
};

I guess this is not too uncommon. But it leads to problems when replacing the following for loop within a function:

function test(someArray) {
  for (var i = 0; i < someArray.length; i++) {
    if (someArray[i] === 23) {
      return true;
    }
  }
  return false;
}

The replacement:

function test(someArray) {
  forEach(someArray, function(i, value) {
    if (value === 23) {
      return true;
    }
  });
  return false;
}

Does not return the function test when 23 is reached and returns true but keeps executing the statements after the forEach and returns false.

Daniel
  • 3,383
  • 4
  • 30
  • 61
  • please add some data and the wanted result. checking for `23` can lead to `true`, `23`, or a collection of `[23, 23]`. – Nina Scholz Feb 11 '17 at 12:28
  • @NinaScholz Well, this is only an example. I am looking for an all purpose solution. I thought maybe there is a way to send a return statement directly further on to the parent function. But probably there is no such thing. – Daniel Feb 11 '17 at 12:31
  • @gavgrif Thanks. Fixed it. – Daniel Feb 11 '17 at 12:32

3 Answers3

1

Your forEach() function needs to return a value. Otherwise of course you will always return false after calling forEach().

function forEach(array, f) {
  var len = array.length, i;
  for (i = 0; i < len; i += 1) {
    if (f(i, array[i], len)) {
        return true;
    }
  }
  return false;
};

function test(someArray) {
  return forEach(someArray, function(i, value) {
    return value == 23;
  });
}
haffla
  • 1,056
  • 8
  • 15
1

First of all, please use for a callback the same style as in the API for array. Then use the callback as check and leave the decision to the calling function to use the information.

In this case the callback looks for a number and return true if the element is equal to 23. The calling function stops the iteration when receiving true and return true. Otherwise the iteration goes on and if not found, the return value is false.

function forEach(array, f) {
    var len = array.length,
        i;

    for (i = 0; i < len; i ++) {
        if (f(array[i], i, array)) {
            return true;
        }
    }
    return false;
}

var cb = function (v) { console.log('value', v); return v === 23; };

console.log('result', forEach([1, 2, 3, 4, 5, 23, 6, 7], cb));
console.log('result', forEach([1, 2, 3, 4, 5, 6, 7, 33], cb));
.as-console-wrapper { max-height: 100% !important; top: 0; }

For a different approach, like to get a value back, I suggest to return the item instead of a boolean value. If not found, return undefined.

function forEach(array, f) {
    var len = array.length,
        i;

    for (i = 0; i < len; i ++) {
        if (f(array[i], i, array)) {
            return array[i];
        }
    }
}

var cb = function (v) { console.log('value', v); return v === 23; };

console.log('result', forEach([1, 2, 3, 4, 5, 23, 6, 7], cb));
console.log('result', forEach([1, 2, 3, 4, 5, 6, 7, 33], cb));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Does the loop get much slower due to the `if` check? – Daniel Feb 11 '17 at 12:58
  • Would your solution take care of, say, two nested `forEach` where the inner function sends the return statement? – Daniel Feb 11 '17 at 13:15
  • 1
    it depends what `forEach` return. the original [`Array#forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) does only iterate with the callback. [`Array#filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) returns an array with the items while the callback retuns a boolean value, as in the above cases. so yes, it could, depending on the staye and purpose of your own `forEach`. – Nina Scholz Feb 11 '17 at 14:45
0

There are several ways of achieving the effect. This is a simple one:

function test(someArray) {
  var result = false

  forEach(someArray, function(i, value) {
    if (value == 23) result = true;
  });

  return result;
}

Note that value should be compared with ==. A single = is for assignment, it just replaces value.

The disadvantage of using forEach here is that the loop won't stop when value is 23. It will finish interating through all the items, even if 23 is the first on the list. With the for-return combo, iteration stops as soon as 23 is found.

If this worries you, there's a trick or two for stopping forEach, but the for-return approach is cleaner.

Community
  • 1
  • 1
salezica
  • 74,081
  • 25
  • 105
  • 166