One would say that the output is Tom, but it isn't. Why?

d is not undefined, but Jerry is the output on the console. How come?

var d = 'Tom';
function zeta() {
	if (d === undefined) {
		var d = 'Jerry';
	}
	console.log(d);
}
zeta();
3 Likes

What a great question! The answer has to do with something called “hoisting”.

When you run javascript code, the computer (technically, something called the “interpreter”) will first do a quick scan of the code and look for variable, class, and function declarations. If it finds any, it “hoists” them up to the top of their scope.

For this explanation, lets just focus on how functions and variables declared with var get hoisted, because that’s where this behavior is seen 99.9% of the time.

Hoisting is why javascript will let you call a function before it’s declared (though you shouldn’t), like this:

print('this works') 
// print hasn't been declared yet, but this still works
// because the function declaration below gets hoisted to the top
function print(message) {
    console.log(message)
}

The print() function declaration gets hoisted above the function call, so to the computer, the code that runs looks more like this:

function print(message) {
    console.log(message)
}
print('this works') 

Technically, hoisting doesn’t really “move” any code, it has more to do with how the computer sets aside memory for your variables, functions, and classes. However, the behavior makes it seem like the code has moved around.

It gets a bit weirder

With variables declared with var, there’s an even trickier behavior. The declarations get hoisted to the global (top-level) scope, but the assignments do not.

That means that after hoisting happens, the computer runs your code as if it looks like this:

var d = 'Tom';
var d; // this was hoisted out of the code block in the if statement
// it has no assignment though, so it's undefined
function zeta() {
	if (d === undefined) {
	  d = 'Jerry'; // notice I removed the var
          // the declaration var d was hoisted
         // the assignment d = 'Jerry' was not hoisted
	}
	console.log(d);
}
zeta();

When this runs, the computer first gives d the value 'Tom'. Then it gives it the value undefined, overwriting 'Tom'. Then the function runs. The if statement checks if d is undefined. It is, so it gives d the value 'Jerry'. Then the console.log prints 'Jerry'

To fix this, use let inside the if statement. Technically it also gets hoisted, but with a much different behavior that won’t cause bugs like this.

There’s some more you can read about this here on MDN.

Hope this helps! Let me know if you have any questions.
Ben

2 Likes

Ok, thanks for that clear expanation.