Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this strange behavior? [duplicate]

Tags:

javascript

I'm modifying a piece of code in 3 ways. In these 3 conditions in is behaving differently. Please describe how it's executing?

var a=1;
function myFunc(){
    console.log(a);
    console.log(a)
}
myFunc();
//Output is:
1 
1

var a=1;
function myFunc(){
    console.log(a);
    var a=2;
    console.log(a)
}
myFunc();
//Output is:
undefined
2

var a=1;
function myFunc(){
    console.log(a);
    var a=2;
    console.log(a)
}
myFunc(a);
//Output is:
undefined
2

Why in 2nd case it's printing undefined? And in 3rd case I'm sending my global a as an argument, then also it's printing undefined.

like image 665
Paul Shan Avatar asked Feb 19 '14 15:02

Paul Shan


2 Answers

That's because JavaScript moves var declarations to the top of the scope, so your code actually is:

var a = 1;
function myFunc(){
    var a;            // a is redeclared, but no value is assigned
    console.log(a);   // therefore it evaluates to undefined
    a = 2;            // now a = 2
    console.log(a);   // and then it logs to 2
}
myFunc();

This behaviour is called Variable Hoisting.

EDIT As Beterraba said, in the third code it logs undefined because no argument was declared in the function's header:

var a = 1;
function myFunc(a) {    // a is declared
    console.log(a);     // now a logs 1
    var a = 2;          // now a = 2
    console.log(a);
}
myFunc(a);
like image 132
Danilo Valente Avatar answered Nov 15 '22 17:11

Danilo Valente


The second case is printing undefined due to the way that JavaScript Execution context works. You might have come across the term hoisting.

To explain it in more details, when the second function is invoked, the interpreter will enter a process with two phases.

Creation stage

  • Creates the scope chain
  • Creates arguments, functions, variables, the so-called variable object
  • Determines the value of "this" keyword

Activation or code execution stage

  • interprets and executes the code

So when you callmyFunc() the JavaScript interpreter will create an execution context which you can think of as an object literal that looks like this:

myFuncExecutionContext = {
   scopeChain: { ... },
   variableObject: {
      arguments: {
        length: 0
      },
     a: undefined,
  },
  this: { ... }
}

You can see that the local a variable has an initial value of undefined. During the code execution stage, the interpreter will run the function line by line; So the first line it sees is the console.log(a);. The interpreter will look at the variableObject to see if there is variable with that name. If not it will use the scope chain and will try to locate it in the variable object of the outer scopes. Since, there is the a variable in the variable object, it will read it's value, which is undefined.

Then it will do to line 2 where it will assign a value to the local variable a; var a=2;. Then it will execute the last line - console.log(a) - which will print the value that we assigned earlier.

The same mechanism justifies why we can invoke a function before it's defined, as long as, we use a function declaration syntax.

someFunc(); // VALID
function someFunc(){  };

Whereas the following will cause an error:

someFunc(); // TypeError: undefined is not a function
var someFunc = function() {  }
like image 37
ppoliani Avatar answered Nov 15 '22 17:11

ppoliani