Javascript for Beginner 1

This is a first post of a little serie : my steps to explain to colleague new to javascript what to know and how to develop app without (too much) headache.

The first thing I explain to someone new to javascript : the unusual way JS variables (var) are scoped, and the (bad) consequence.

Javascript is function scoped

What does that mean exactly. Well usually (in other language) variables are block scoped. That means this (example in C) :

int im_alive = 0;

if (im_alive)
{
  // im_alive_only_here will be dealocated at the end of this block
  int im_alive_only_here = 1;
  printf("im_alive_only_here = %d", i_will_die_soon);
}

printf("im_alive = %d", i_will_die_soon);

// Error: im_alive_only_here is not reachable here
printf("im_alive_only_here = %d", im_alive_only_here);

With javascript a similar code (using ‘var’ in place of ‘int’), im_alive_only_here is reachable even outside the if block scope.

And this can lead the programmer to amusing mistakes, notably in a for loop.

Classic mistake : reference in a loop

JS is function scoped so this code will not work as intended :

var arr = [];
for (var i=0; i<5; i++) { // let's create 5 functions
  arr[i] = function() {   // and store them in arr
    console.log(i + '.'); // each should log its value.
  };
}
for (var j=0; j<arr.length; j++) {
  arr[j]();               // and now let's run each one to see
}

If you except the result to be “0.1.2.3.4.” you may be surprised to get “5.5.5.5.5.”

Because JS is function scoped the variable i is a reference to the function block, not the for loop block. So i will refer to 5 which is the last value in the loop ; and the function assignment will refer to i.

☑ use a closure to solve reference in loop problem

To fix this : encapsulate usage in an other function (here we use an anonymous function, but you can declare a create function), aka “closure”. Check the 2 lines added (marked with ‘<–’) :

var arr = [];
for (var i=0; i<5; i++) {   // let's create 5 functions
  // create an anonymous fuction to limit k scope
  (function(k) { // <-- k is not a reference in the for
    arr[i] = function() {  // and store them in arr
      console.log(k + '.');// each should log its value using k
    };
  })(i); // <-- this line make k=i in the anonymous function scope
}
for (var j=0; j<arr.length; j++) {
  arr[j]();                // and now let's run each one to see
}

This will output the intended “0.1.2.3.4.”

A better solution … but need ES6

If you have chance to develop for ES6 enabled environment, you can use let and const instead of var :

  • let : same as var but block scoped
  • const : same as let but can be assigned only once and has to be assigned at declaration

If you can use ES6 let and const, you should use it and never use again var.

Note: let is usable with IE-11, Edge, FF-44, Chrome-49, Opera-36 … but sadly seems to be bugged in Safari 10