Variable scope

The scope of variables in JavaScript is not natural. In fact, sometimes it's downright counter-intuitive. They say that JavaScript programmers can be judged by how well they understand scope.

Scope resolutions

First, let's go over the different scope resolutions in JavaScript.

JavaScript uses scope chains to establish the scope of variables. When resolving a variable, it starts at the innermost scope and searches outwards.

Global scope

Variables, functions, and objects defined at this level are available to any code in the entire program. This is the outermost scope.

var x = 'hi';
function a() {
  console.log(x);
}
a(); // 'hi'

Local scope

Each function described has its own local scope. Any function defined within another function has a nested local scope that is linked to the outer function. Almost always, it's the position in the source that defines the scope.

var x = 'hi';
function a() {
  console.log(x);
}
function b() {
  var x = 'hello';
  console.log(x);
}
b(); // hello
a(); // hi

Local scope is only for functions and not for any expression statements (if, for, while, and so on), which is different from how most languages treat scope.

function c() {
  var y = 'greetings';
  if (true) {
    var y = 'guten tag';
  }
  console.log(y);
}

function d() {
  var y = 'greetings';
  function e() {
    var y = 'guten tag';
  }
  console.log(y)
}
c(); // 'guten tag'
d(); // 'greetings'

In functional programming, this isn't as much of a concern because functions are used more often and expression statements less often. For example:

function e(){
  var z = 'namaste';
  [1,2,3].foreach(function(n) {
    var z = 'aloha';
  }
  isTrue(function(){
    var z = 'good morning';
  });
  console.log(z);
}
e(); // 'namaste'

Object properties

Object properties have their own scope chains as well.

var x = 'hi';
var obj = function(){
  this.x = 'hola';
};
var foo = new obj();
console.log(foo.x); // 'hola'
foo.x = 'bonjour';
console.log(foo.x); // 'bonjour'

The object's prototype is further down the scope chain.

obj.prototype.x = 'greetings';
obj.prototype.y = 'konnichi ha';
var bar = new obj();
console.log(bar.x); // still prints 'hola'
console.log(bar.y); // 'konnichi ha'

This isn't even close to being comprehensive, but these three types of scope are enough to get started.

Closures

One problem with this scope structure is that it leaves no room for private variables. Consider the following code snippet:

var name = 'Ford Focus';
var year = '2006';
var millage = 123456;
function getMillage(){
  return millage;
}
function updateMillage(n) {
  millage = n;
}

These variables and functions are global, which means it would be too easy for code later down the program to accidentally overwrite them. One solution would be to encapsulate them into a function and call that function immediately after defining it.

var car = function(){
  var name = 'Ford Focus';
  var year = '2006';
  var millage = 123456;
  function getMillage(){
    return Millage;
  }
  function updateMillage(n) {
    millage = n;
  }
}();

Nothing is happening outside the function, so we ought to discard the function name by making it anonymous.

(function(){
  var name = 'Ford Focus';
  var year = '2006';
  var millage = 123456;
  function getMillage(){
    return millage;
  }
  function updateMillage(n) {
    millage = n;
  }
})();

To make the functions getValue() and updateMillage() available outside the anonymous function, we'll need to return them in an object literal as shown in the following code snippet:

var car = function(){
  var name = 'Ford Focus';
  var year = '2006';
  var millage = 123456;
  return {
    getMillage: function(){
      return millage;
    },
    updateMillage: function(n) {
      millage = n;
    }
  }
}();
console.log( car.getMillage() ); // works
console.log( car.updateMillage(n) ); // also works
console.log( car.millage ); // undefined

This gives us pseudo-private variables, but the problems don't stop there. The following section explores more issues with variable scope in JavaScript.

Gotchas

Many variable scope nuances can be found throughout JavaScript. The following is by no means a comprehensive list, but it covers the most common cases:

  • The following will output 4, not 'undefined' as one would expect:
    for (var n = 4; false; ) { } console.log(n);

    This is due to the fact that, in JavaScript, variable definition happens at the beginning of the corresponding scope, not just when it is declared.

  • If you define a variable in the outer scope, and then have an if statement define a variable inside the function with the same name, even if that if branch isn't reached, it is redefined. An example:
    var x = 1;
    function foo() {
      if (false) {
        var x = 2;
      }
      return x;
    }
    foo(); // Return value: 'undefined', expected return value:
    2

    Again, this is caused by moving the variable definition at the beginning of the scope with the undefined value.

  • In the browser, global variables are really stored in the window object.
    window.a = 19;
    console.log(a); // Output: 19

    a in the global scope means a as an attribute of the current context, so a===this.a and window object in a browser act as an equivalent of the this keyword in the global scope.

The first two examples are a result of a feature of JavaScript known as hoisting, which will be a critical concept in the next section about writing functions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.35.72