Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript- Variable Hoisting

Tags:

javascript

This is a simple snippet, I just dont understand something.

The below code outputs 12, I understand that, because the var foo = 12; replaces the previous declaration of the variable.

<script>
var foo = 1;
function bar(){
  if (!foo) {
    var foo = 12;
  }
  alert(foo);
}
bar();
</script>

In the below code, it alerts 1 , which means the variable declared outside the function is accessible inside the function.

  <script>
    var foo = 1;
    function bar(){
      alert(foo);
    }
    bar();
    </script>

But, in the below code, why it alerts undefined ?? I thought, it will alert 1, I am just assigning the previously declared variable to the new one.

  <script>
    var foo = 1;
    function bar(){
      if (!foo) {
        var foo = foo;
      }
      alert(foo);
    }
    bar();
    </script>
like image 834
Abhinav Avatar asked Nov 05 '15 09:11

Abhinav


4 Answers

Variable declarations are pushed to the start of the function.

Therefore in reality the following is happening:

function bar(){
      var foo;
      if (!foo) {
        foo = foo;
      }
      alert(foo);
}

Therefore you would need to change this to use window.foo so that you're referring to the global property rather than the function's property:

var foo = 1;
function bar(){
   var foo;
   if (!window.foo) {
      foo = window.foo;
   }
   alert(foo);
}
bar();
like image 158
Curtis Avatar answered Oct 12 '22 22:10

Curtis


Hoisting is slightly tricky. Function declarations are hoisted with the function assignment, but variable declarations are hoisted without the variable assignment. So the execution order of code is actually:

var foo;
var bar = function bar(){
  var foo; // undefined
  if (!foo) { // true
    foo = foo; // foo = undefined
  }
  alert(foo);
}
foo = 1;
bar();

You could either use window.foo if you want to refer to the global variable foo, or better, just use a different variable name:

var foo = 1;
function bar(){
  var baz =  foo;
  alert(baz);
}
bar();
like image 38
nils Avatar answered Oct 12 '22 23:10

nils


The below code outputs 12, I understand that, because the var foo = 12; replaces the previous declaration of the variable.

var foo = 1;
function bar(){
  if (!foo) {
    var foo = 12;
  }
  alert(foo);
}
bar();

You are right because local variable overriding the global one.

In the below code, it alerts 1 , which means the variable declared outside the function is accessible inside the function.

var foo = 1;
function bar(){
  alert(foo);
}
bar();

You are correct. foo is declare in global scope so is accessible fron anywhere.

But, in the below code, why it alerts undefined ?? I thought, it will alert 1, I am just assigning the previously declared variable to the new one.

var foo = 1;
function bar(){
  if (!foo) {
    var foo = foo;
  }
  alert(foo);
}
bar();

This is a bit different. You are declaring a global variable and a local one with the same name. When your JavaScript program execution enters a new function, all the variables declared anywhere in the function are moved (or elevated, or hoisted) to the top of the function.

Another example:

var a = 123;

function f() {
    var a; // same as: var a = undefined;
    alert(a); // undefined
    a = 1;
    alert(a); // 1
}
f();
like image 24
Alex Char Avatar answered Oct 13 '22 00:10

Alex Char


In javascript, until the ES5 specification, the scope is implemented only in terms of function body. The concept of block scope doesn't exist (really, will be implemented in the next javascript with the let keyword).

So, if you declare a variable var something; outside from function body, it will be global (in browsers global scope is the scope of the window object).

  1. global variables

var something = 'Hi Man';

/**
 * this is equal to:
**/

window.something = 'Hi Man';

If your code doesn't run in strict mode, there is another way to declare a global variable: omitting the var keyword. When the var keyword is omitted the variable belongs (or is moved) to the global scope.

  1. example:

something = 'Hi Man';

/**
 * this is equal to:
**/

function someFunction() {
  something = 'Hi Man';
}

Local Variables

Because the non-existence of block scopes the only way to declare a local variable is to define it in a function body.

  1. Example

var something = 'Hi Man'; //global
console.log('globalVariable', something);

function someFunction() {
  var something = 'Hi Woman';
  console.log('localVariable', something);
  
  /**
   * defining variable that doesn't exists in global scope
  **/
  var localSomething = 'Hi People';
  console.log('another local variable', localSomething);
}

someFunction();
console.log('globalVariable after function execution', something);

try {
  console.log('try to access a local variable from global scope', localSomething);
} catch(e) { console.error(e); }

As you can see in this example, local variables don't exist outside from their scope. This means another thing... If you declare, with the var keyword, the same variable in two different scopes you'll get two different variables not an override of the same variable (name) defined in the parent scope.

If you want to "override" the same variable in a child scope you have to use it without the var keyword. Because of the scope chain if a variable dosn't exist in a local scope it will be searched on their parent scope.

  1. Example

function someFunction() {
  something = 'Hi Woman';
}

var something = 'Hi Man';
console.log(1, 'something is', something);


someFunction();
console.log(1, 'something is', something);

Last thing, variable hoistment.

As I wrote below, at the moment, there isn't any way to declare a variable in some point of your code. It is always declared at the start of it scope.

  1. Example

function someFunction() {
  // doing something
  
  // doing something else
  
  var something = 'Hi Man';
}


/**
 * Probably you expect that the something variable will be defined after the 'doing 
 * something else' task, but, as javascript works, it will be defined on top of it scope.
 * So, the below snippet is equal to:
**/

function someFunction1() {
  var something;
  
  // doing something
  
  // doing something else
  
  something = 'Hi Man';
}

/**
 * You can try these following examples: 
 *
 * In the someFunction2 we try to access on a non-defined variable and this throws an
 * error.
 *
 * In the someFunction3, instead, we don't get any error because the variable that we expect to define later will be hoisted and defined at the top, so, the log is a simple undefined log.
**/

function someFunction2() {
  console.log(something);
};

function someFunction3() {
  console.log('before declaration', something);
  
  var something = 'Hi Man';
  
  console.log('after declaration', something);
}

This happens because in javascript there are two different steps of a variable declaration:

  • Definition
  • Initialization

And the function3 example becomes as following:

function3Explained() {
  var something; // define it as undefined, this is the same as doing var something = undefined;
  
  // doing something;
  // doing something else;
  
  something = 'Hi Man';
  
}
like image 35
Hitmands Avatar answered Oct 12 '22 22:10

Hitmands