Reputation: 565
Looking for best practice advice.
Is it a good practice to have function call in for of as iterable object?
const obj = {key1:'a', key2:'b'};
for(const i of Object.keys(obj)){ ... }
or better to have
const obj = {key1:'a', key2:'b'};
const allKeys = Object.keys(obj);
for(const i of allKeys){ ... }
Isn't Object.keys function called on every iteration of the loop?
Upvotes: 1
Views: 205
Reputation: 350365
The call to Object.keys
is only made once in both variants.
But consider also as possibility this for
loop that does not depend on Object.keys
:
for (const prop in obj) { }
Object.keys
creates an array, while the above for
loop does not. The latter only retrieves the items as necessary. Of course, if your for
loop is never exited prematurely, it will still retrieve all of them, so this only makes a difference when you plan to exit the loop prematurely. In that case the corresponding iterator never visits the remaining items, while Object.keys
would already have done so in creating the array.
One thing to pay attention to: a for .. in
loop will also iterate enumerable inherited properties, not only own properties, while Object.keys
will only list own enumerable properties. You can add an extra test in the for
loop to exclude non-own properties:
if (obj.hasOwnProperty(prop))
Upvotes: 0
Reputation: 1074595
Your first example does the same thing as the second, just without the allKeys
constant. In your first example:
const obj = {key1:'a', key2:'b'};
for(const i of Object.keys(obj)){ ...
...Object.keys
will only get called once, and then its iterator will be retrieved and used for the loop. (This is covered in ForIn/OfHeadEvaluation in the spec, but it's...heavy going.) So you're fine using that form, it's not inefficient.
Upvotes: 2
Reputation: 10458
you can check it by mocking a similar case
function A(){
console.log('function called');
return [1, 2, 3, 4, 5];
}
for(let i of A()){
console.log(i);
}
As you can see A() is called only once
Upvotes: 6