How does "each" differ from a for-loop when returning a value?

I have my function each

that I created to emulate Underscore.js _each()

for my Javascript research.

var each = function(list, iteratee) {
    if (Array.isArray(list)) { // list is array
        for (var i = 0; i < list.length; i++) {
            iteratee(list[i], i, list);
        }
    } else if (list.constructor === Object) { // list is object
        for (var key in list) {
            iteratee(list[key], key, list);
        }
    }
};

      

Then I wanted to create a function find

that is also available from Underscore.js. This function list

loops through each value in , returning the first one that passes the truth test ( predicate

), or undefined

if the value fails the test. The function returns as soon as it finds an acceptable element and does not traverse the entire list.

Here is my version find

that I ran into.

var find = function(list, predicate) {
    each(list, function(elem){
        if (predicate(elem)) {
            return elem;
        }
    });
};

      

I thought it would return the value immediately after it finds the true value for the item that passes the test from the outer predicate function. But instead he gives it to me undefined

.

Below code works as I expected. But why do they provide different results?

var find = function(list, predicate) {
    if (Array.isArray(list)) { // list is array
        for (var i = 0; i < list.length; i++) {
            if (predicate(list[i])) {
                return list[i];
            }
        }
    } else if (list.constructor === Object) { // list is object
        for (var key in list) {
            if (predicate(list[key])) {
                return list[key];
            }
        }
    }
};

      

I don't understand why it doesn't work each

as I expected when I included it in my function find

. Wouldn't they just be different in terms of their style of expression? In other words, one is functional and the other is not?

+3


source to share


2 answers


It has to do with how it works return

. Look at your code:

var find = function(list, predicate) {
    // you pass list and an anonymous callback to `each`
    each(list, function (elem) {
        // if this condition is true
        if (predicate(elem)) {
            // return elem
            return elem;
        }
    });
}

      

The problem is that return elem

applies to anonymous postback, not function find

.

If you want to "break" the loop each

, you can check the current state at each iteration of the for loop inside each

.



// only going to write for arrays
var each = function (list, iteratee) {
    for (var i = 0; i < list.length; i++) {
        if (iteratee(list[i], i, list)) continue;
        else break;
    }
});
// then in find:
var find = function (list, predicate) {
    var ret = null
    each(list, function(elem) {
        if (predicate(elem)) {
            ret = elem;
            return false;    // return false, since we no longer wish to continue
        }
    });
    return ret;
};

      

The second solution is to return from the loop each

:

var each = function (list, iteratee) {
    for (var i = 0; i < list.length; i++) {
        if (iteratee(list[i], i, list)) {
            continue;
        } else {
            return list[i];
        }
    }
    // didn't find anything, so `return null`
    return null;
});
var find = function (list, predicate) {
    return each(list, function(elem) {
        // if `predicate`, return false, so the loop breaks
        return !predicate(elem);
    });
};

      

The only problem with this solution is that it distorts the meaning each

. each

intuitively means "pass all", which the second solution does not necessarily do.

+1


source


This is caused by the absence of a return statement. Each function iterates over the search, but returns nothing. return in a predicate returns the result of each function where it is not expected

An example of a work function:



var find = function(list, predicate) {
     var res = undefined/null/whatever;
     each(list, function(elem) {
         if (predicate(elem)) {
             res = elem;
         }
     });
     return res;
};

      

However, this function is ineffective as it does not stop when a result is found.

+2


source







All Articles