4

I have the sample code:

var t = 20;
function test () {
  console.log(t);
    var t = 100;
}
test();

The result will be undefined. I thought t was global variable, so why, when I log it, is it undefined?

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
Hoc N
  • 143
  • 3
  • 12

3 Answers3

5

The scope of a variable is the reason why you're seeing this. From the MDN documentation on var:

var hoisting

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.

Variables in JavaScript are function-scoped, meaning they only exist in the function. Since variable declarations are processed before any execution of code, they are declared are the beginning of the enclosing function-scope. This "pre-processing" is called "hoisting", as the declaration is hoisted up to the beginning of the enclosing function-scope. Since you redeclare t inside the function, it's declared at the beginning of the function (because variables are function-scoped) and is equivalent to this:

var t = 20;
function test () {
    var t;
    console.log(t);
    t = 100;
}
test();

Since t is never given a value before you assign it after the logging, it's undefined. The solution is to remove the var redeclaration. Thus, no declaration of a variable is seen in the function and nothing is hoisted.


Note that this hoisting procedure is the same reason why you can use function declarations before they're defined:

foo(); //logs "foo called!"

function foo() {
    console.log("foo called!");
}

Function declarations (and only declarations) are hoisted like variables (but instead, the whole declaration is hoisted, not just the name). Thus, the function is declared before any execution happens, and when the code is run, foo is called as it's already declared.

Community
  • 1
  • 1
Andrew Li
  • 55,805
  • 14
  • 125
  • 143
2

From MDN:

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.

What this means is that your function's declaration of a new t variable is effectively performed at the opening of the function. This immediately obscures the "global" t variable with the local one. However, the line of code which sets a value to that new t variable doesn't execute until after you log to the console. So the default value is undefined.

Perhaps not the most intuitive feature of JavaScript in this example, I'll admit. But at the same time it highlights the importance of clarity in your code. Having two variables of the same name even attempt to be accessible in the same scope is a potential source for bugs. It would be better to give them different names.

David
  • 208,112
  • 36
  • 198
  • 279
0

t is both global and local.

When you are inside a function there is something called scope. This means you can declare variables with the same names as global ones and they will actually be completely different. Now notice where you place console.log(). If you did not decalre a variable t inside your function you would log 20 however you did so the function is concerned with the function's t. But you are logging before the t was declared!

var t = 20;
function test () {    
    console.log(t);
}
test();

var t = 20;
function test () {
    console.log(t);
    var t = 100;
}
test();

Your code is equivalent to: (the var is moved to the top without being defined. Something called hoisting.)

var t = 20;
function test () {
    var t;
    t = 100;
     console.log(t);
}
test();
Turnipdabeets
  • 5,815
  • 8
  • 40
  • 63