JavaScript the Fun Part


effective-javascript-2

types-of-for-loop


Quick reviewing of three types of for loop in JavaScript.

for loop

A common for loop we can find in any other programming languages with these structure:

This for loop is based on indexing which means usually we use it when we have an array and want to iterator over it.

// simple array
const log = console.log.bind( console );
const array = [ 1, 2, 3 ];
const max = array.length;
for( let index = 0; index < max; ++index ){
    log( array[ index ] ); // accessing by using index of the array
}

// output
1
2
3

Two issues with this for are

  1. noticing the array length boundary
  2. using index variable for the array

And since other that using arrays we use too much object and wants to iterate over them we will face something like this:

// simple object
const log = console.log.bind( console );

const object = {
    x: "this is x",
    y: "this is y",
    z: "this is z"
};

log( object.length ); // undefined

// extract the keys method with fixed this binding 
const keys = Object.keys.bind( Object );

// array of keys
const objectKyes = keys( object );

// length of array
const objectLength = objectKyes.length;

// iterating over the object
for( let index = 0; index < objectLength; ++index ){
    // each key
    // x, y, z
    const key = objectKyes[ index ];
    log( object[ key ] );
}

// output
this is x
this is y
this is z

Maybe someone simplify it to this:

// forEach method of Array
keys( object ).forEach(function( key ){ log( object[ key ] )});

// output
this is x
this is y
this is z

This way is okay, but we know what the forEach method does.

More Info

for in

The for ... in statement iterates over all non-Symbol, enumerable properties of an object.

So the main purpose of for ... in is to iterator over an object that has enumerable properties.

When we have enumerable properties:

 // create an empty object, no inheritance
const log = console.log.bind( console );
const emptyOjbect = Object.create.bind( Object, null );

const object = emptyOjbect();
object.x = "this is x";
object.y = "this is y";
object.z = "this is z";

for( const key in object ){
    log( object[ key ) );
}

// output
this is x
this ix y
this is z

When we do not have it:

 // create an empty object, no inheritance
const log = console.log.bind( console );
const emptyOjbect = Object.create.bind( Object, null );

const object = emptyOjbect({
    x: {
        value: 'this is x'
    },
    y: {
        value: 'this is y'
    },
    z: {
        value: 'this is z'
    }
});

for( const key in object ){
    log( object[ key ] );
}

// output
undefined

Why?

Simply because here each property in our object has an attribute named: enumerable and the way we created above set them to false so the for ... in loop cannot iterator over it.

Thus for .. in cannot iterator over non-enumerable properties.

Please notice that we declaring key variable we used const keyword and it worked.

Using the constant variable means that for each iteration this variable is created and assigned. So three different ones, separately, each time.

Just for testing lets make one of them enumerable

 // create an empty object, no inheritance
const log = console.log.bind( console );
const emptyOjbect = Object.create.bind( Object, null );

const object = emptyOjbect({
    x: {
        value: 'this is x'
    },
    y: {
        value: 'this is y',
        enumerable: true
    },
    z: {
        value: 'this is z'
    }
});

for( const key in object ){
    log( object[ key ] );
}

// output, only object.y is enumerable, not x,z
this is y

for of

The for...of statement creates a loop iterating over iterable objects, including: built-in String, Array, Array-like objects (e.g., arguments or NodeList), TypedArray, Map, Set, and user-defined iterables. It invokes a custom iteration hook with statements to be executed for the value of each distinct property of the object.

While for ... in is a specific statement for iterating over objects, for ... of which added in ES6 is for iterable objects.

Iterable objects means these that we can use their index, a kind of array.

for ... of with an object:

for( const key of { x: 'X', y: 'Y' } ) console.log( key );

// output
TypeError: ({x:"X", y:"Y"}) is not iterable

for ... in with the same object:

for( const key in { x: 'X', y: 'Y' } ) console.log( key );

// output
x
y

Thus keep in mind that objects are not iterable, they are enumerable.

But arrays are both iterable and enumerable!

Using for ... of with an array:

for( const key of [ 10, 20, 30 ] ) console.log( key );

// outout
10
20
30

Using for ... in with the same array:

for( const key in [ 10, 20, 30 ] ) console.log( key );

// output ( indexes of our array )
0
1
2

And finally for loop is faster than for ... in or for ... of, but not safer.

for ... in, for ... of are safer and simpler to use.


Update: Sun Sep 15 2019 20:00:34 GMT+0430 (Iran Daylight Time)