Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need to understand Javascript function hoisting example

Tags:

I read the concept of Javascript Hoisting.Its pretty confusing but I saw some examples and got the idea what hoisting actually does.

So basically "Hoisting is JavaScript's default behavior of moving all declarations to the top of the current scope (to the top of the current script or the current function)."

But I am not able to understand the below implementation :

var is_android = true; if (is_android) {     function foo() {         alert('I am Android');     } } else {     function foo() {         alert('I am NOT Android');     } } foo(); 

The output shows "I am NOT Android" in alert box.

I want to know why foo() is called from else block even if is_android value is true .

Any help will be appreciated.

like image 496
Siddharth_Vyas Avatar asked Apr 17 '14 05:04

Siddharth_Vyas


People also ask

What is hoisting in JavaScript explain with example?

Hoisting in JavaScript is a behavior in which a function or a variable can be used before declaration. For example, // using test before declaring console.log(test); // undefined var test; Run Code. The above program works and the output will be undefined .

How functions are hoisted in JavaScript?

Hoisting is a JavaScript technique which moves variables and function declarations to the top of their scope before code execution begins. Within a scope no matter where functions or variables are declared, they're moved to the top of their scope.

Does function get hoisted in JavaScript?

In JavaScript, the default action is for declarations to be moved to the top of the code. Declarations are moved to the top of the current scope by the JavaScript interpreter, meaning the top of the current function or scripts. All functions and variables are hoisted.

What is the benefit of hoisting in JavaScript?

Hoisting is JS's default behavior of defining all the declarations at the top of the scope before code execution. One of the benefits of hoisting is that it enables us to call functions before they appear in the code. JavaScript only hoists declarations, not initializations.


2 Answers

tl;dr: Don't use something that looks like a function declaration inside a block, especially not a conditional.


Fact is, most browsers interpret this piece of code the wrong way. They treat the function definitions as function declarations, even though function declarations are not allowed inside blocks, since a function declaration is not a statement, it's a source element.

This how it works in general:

Before the code is even executed, the interpreter looks for all variable and function declarations, not matter where they are, and creates a binding for them in the current/new environment. Then it starts actually executing the code.

So, assuming that the function definitions are interpreted as declarations, since there are two declarations, the last one wins. Your code basically becomes:

function foo() {     alert('I am Android'); } function foo() {     alert('I am NOT Android'); } var is_android;  is_android = true; if (is_android) {  } else {  } foo(); 

Other engines would interpret it differently, but still incorrectly (IMO, see below):

In the following script, the zero function is never defined and cannot be invoked, because 'if (0)' evaluates its condition to false:

if (0) {    function zero() {       document.writeln("This is zero.");    } } 

Note: Some JavaScript engines, not including SpiderMonkey, incorrectly treat any function expression with a name as a function definition. This would lead to zero being defined, even with the always-false if condition. A safer way to define functions conditionally is to define the function anonymously and assign it to a variable:

if (0) {    var zero = function() {       document.writeln("This is zero.");    } } 

But in this case, if the function definition truly was interpreted as function expression (similarly to (function zero() { ... })), then the name of the function would not be accessible in the containing scope, and the function would just be lost.

like image 87
Felix Kling Avatar answered Oct 11 '22 14:10

Felix Kling


In Javascript there are subtle differences between the two similar-looking

 function square(x) { return x*x; } 

and

 var square = function(x) { return x*x; } 

The biggest difference is that in the first case the assignment of the function object to the square name is done when entering the scope, not when reaching the line. This allows for calling functions that are defined later in the source code... for example:

console.log(cube(12)); function cube(x) { return x*x*x; } 

is a valid script that will work, even if the call happens "before" the function definition (and, by the way, allowing this kind of code is IMO the reason for the rule being in the language).

In the second case instead the assignment is just a regular statement and it's executed when (and if) the flow of control passes through it.

If you want that snippet to work as you expect then simply change the code from

function <name> (...) { ... } 

to

var <name> = function (...) { ... } 

PS: you can repeat the name also in the second form, but it's not normally done and anonymous functions are used instead.

like image 39
6502 Avatar answered Oct 11 '22 14:10

6502