I have a function that looks through an array of objects and returns an array of all objects that have matching property and value pairs. This works fine but I always get the notification: "Don't make functions within a loop".
So is this a bad approach to use a function within a loop?
function where(collection, source) {
var arr = [];
var keys = Object.keys(source);
// What's in a name?
for(var i = 0; i < collection.length; i++){
if(keys.every(function(x){return x in collection[i] && source[x] == collection[i][x];})){
arr.push(collection[i]);
}
}
return arr;
}
where([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });
2 Answers 2
You'd be better off defining the function outside of the loop and calling it by passing it parameters. What the warning is referring to in this case is creating a new function object in a loop, meaning you create several anonymous functions, where 1 function would do. Creating a new function object in a loop like this can hurt performance.
As @Pimgd explained, it's not good to recreate an anonymous function in every iteration of a loop. Move the function outside of the loop:
function where(collection, source) {
var arr = [];
var keys = Object.keys(source);
function match(x) {
return x in collection[i] && source[x] == collection[i][x];
}
for (var i = 0; i < collection.length; i++) {
if (keys.every(match)) {
arr.push(collection[i]);
}
}
return arr;
}
I suggest to go one step further. Instead of creating an array and appending to it, you can benefit from the Array.prototype.filter method:
function where(collection, search) {
function filter(item) {
function matchSearchValue(key) {
return key in item && search[key] == item[key];
}
return Object.keys(search).every(matchSearchValue);
}
return collection.filter(filter);
}
Finally, notice how I renamed everything to better explain their purpose.