L0cu2s
L0cu2s

Reputation: 565

Function call as iterable in for of loop ES6

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

Answers (3)

trincot
trincot

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

T.J. Crowder
T.J. Crowder

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

marvel308
marvel308

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

Related Questions