admin管理员组

文章数量:1303670

I noticed a strange behaviour, at least one I don't understand, while returning value inside an underscore each loop. My code is the following, it basically test wether or not an element is already present in an array based on its id, like this :

var elements = [{id: "1", name : "foo"},{id : "3", name: "bar"}];

element_exists = function(key, val){
    _.each(elements,function(element){
        console.log(element[key], val);
        if(element[key] == val){
            console.log("element exists");
                return true;
        }
   });
   return false;
};

console.log("true : ", element_exists("id", "1"));
console.log("false : ", element_exists("id", "2"));

I get the following log in the console :

1 1
element exists
3 1
true : false
1 2
3 2
false : false

My question is why does the function does not return true for the first element ?

I noticed a strange behaviour, at least one I don't understand, while returning value inside an underscore each loop. My code is the following, it basically test wether or not an element is already present in an array based on its id, like this :

var elements = [{id: "1", name : "foo"},{id : "3", name: "bar"}];

element_exists = function(key, val){
    _.each(elements,function(element){
        console.log(element[key], val);
        if(element[key] == val){
            console.log("element exists");
                return true;
        }
   });
   return false;
};

console.log("true : ", element_exists("id", "1"));
console.log("false : ", element_exists("id", "2"));

I get the following log in the console :

1 1
element exists
3 1
true : false
1 2
3 2
false : false

My question is why does the function does not return true for the first element ?

Share Improve this question asked Oct 25, 2013 at 7:00 ltbeshltbesh 6671 gold badge10 silver badges24 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

@ltbesh You are getting it wrong! The function does return the value & stop. It only continues executing the iterator function for the remaining elements in the input.

You are confusing loop statements with _.each method.

The second parameter to the _.each method is an iterator function. It is basically a function that is executed for every element of the array. So, if you write a return statement in your iterator function, it only terminates that particular function call. The function continues to be called for the remaining elements in the array.

Update


UnderscoreJS solution

What you need to use instead is _.find or _.some underscore methods. (Well, now that its 2020 it is high time we abandon using underscore and lodash to get functionality that ES6 provides out-of-the-box). But, since the question is about underscoreJS, I'll first provide a solution using underscore.

var elements = [{id: "1", name : "foo"},{id : "3", name: "bar"}];

element_exists = function(key, val){
    return _.find(elements,function(element){
        return element[key] === val;
   });
};

console.log("true : ", element_exists("id", "1"));
console.log("false : ", element_exists("id", "2"));
<script src="https://underscorejs/underscore-min.js"></script>

ES6 based solution

Now, just to show how succinct it is to acplish the same functionality in ES6 without any external library, here's the ES6 version:

var elements = [{id: "1", name : "foo"},{id : "3", name: "bar"}];

element_exists = (key, val) => (
    elements.find(element => element[key] === val)
)

console.log("true : ", element_exists("id", "1"));
console.log("false : ", element_exists("id", "2"));

PS: If you only want to check if the element exists and don't want it to be returned by your element_exists method, switch from using find to some.

This is happening because you're always returning false from the function.

Rewrite to this if you want to keep on using the each() function.

var elements = [{id: "1", name : "foo"},{id : "3", name: "bar"}];

element_exists = function(key, val){
  var someFlag = false;  
  _.each(elements, function(element){
        console.log(element[key] +" - "+ val);
        if(element[key] == val){
            console.log("element exists");
            someFlag = true;
        }
   });
   return someFlag;
};

console.log("should be true : " + element_exists("id", "1"));
console.log("should be false : " +element_exists("id", "2"));

A bit late, but the accepted answer did not provide a solution so:

Underscore suggests to use the function _.find, which iterates over a list of values and returns the first one that passes a truth test, and undefined otherwise.

This way you can break out of the loop. However, since the return value is the actual element instead of a boolean, you may, upon calling your function, add a wrapper to return true if the function returned a defined value.

_.some might also apply better to your use case.

Sources:

http://underscorejs/#each

http://underscorejs/#find

http://underscorejs/#some

本文标签: javascriptReturning value in underscore each loop does not stop the functionStack Overflow