Why do function declarations get hoisted and function expressions don't? - javascript

According to hoisting definition:
Hoisting is a JavaScript mechanism where variables and function
declarations are moved to the top of their scope before code execution
Why do function declarations get hoisted and function expressions don't?

As per MDN,
Conceptually, for example, a strict definition of hoisting suggests that variable and function declarations are physically moved to the top of your code, but this is not in fact what happens. Instead, the variable and function declarations are put into memory during the compile phase, but stay exactly where you typed them in your code.
As you see, in a function expression, actual function is a value assigned to a named variable. So this named variable is hoisted. Even if you have a named function assigned, it still will not be hoisted as it is not a declaration and will be created later.
Sample:
function test() {
console.log(fn, foo);
var fn = function foo() {}
}
test();

Related

Are function parameters in JavaScript hoisted?

function foo(a,b){
return a + b;
}
foo(1,2);
Are function parameters hoisted?
Does the variableEnvirnoment at the creation phase of the function execution context looks something like that :
VE = {
{ 0 : undefined , 1: undefined, length: 2 },
{a : undefined, b: undefined},
outer: refToGlobalLE
}
Yes, parameters are hoisted.
When a function is called, each declaration in the function body (var, let, const, and function declarations) is instantiated in the environment record for that execution context. Each formal parameter is also added to the environment record in the same way ([9.2.10 21.c.i and 9.2.10 28.e.i.2]). The full process is described in section 9.2.10 of the spec.
Formal parameters and function declarations are both initialised (note: not "instantiated") during the abstract operation called FunctionDeclarationInstantiation. All other bindings are initialized during evaluation of the function body.
This means that formal parameter bindings are added into the same logical location, in the same way, as those of function body declarations ie. var, let, const, and function declarations (all of which are hoisted, by the way). And it means that formal parameter bindings are initialized in the same way as function declarations (ie. that their corresponding value is set at the top of the function).
Hoisting is a function of the time and place an identifier binding is instantiated. Formal parameter bindings are instantiated (and initialized) in the same way as function declarations. We know function declarations are hoisted, therefore parameter bindings are hoisted. QED.
Prior to ES2015 this hoisting was, as far as I know, invisible, because function parameters are already at the very top of a function. However, parameter default value initializer syntax was added in ES2015, making the hoisting visible in userland.
If formal parameters were not hoisted then the following code would not throw "Uncaught ReferenceError: Cannot access 'x' before initialization" because the default parameter value for z would refer to the outer x:
var x = 'global'
(function(y, z = x, x) {}()) // "Uncaught ReferenceError: Cannot access 'x' before initialization"
Your comment says that 'assuming that parameters are hoisted, x would [be initialized to] "undefined", and as a result the error would not occur as x is already initialized'. Your implication is that hoisting could also be used to explain the absence of an error. This is true, but it does not therefore follow that if an error is observed, hoisting cannot be occurring. Indeed, we can see hoisting is occurring because, as specified in the error message, x in z = x is taken to refer to formal parameter x which is declared later in the program text. The only way this is possible is for hoisting to have occurred.
No, The functions parameters are not hoisted in JavaScript.
function foo(a,b){
return a + b;
}
foo(1,2);
To explain you in brief about the whole process, I would like to explain about how the function itself gets called.
So since you are speaking about the variable environment(which in this case would be the global execution context), the JavaScript thread of execution which basically executes the code line by line would store the function definition code as a value to the foo variable in the memory and it does not executes it yet (it just saves the definition as is). It moves to the next execution line which apparently makes a function call(using parenthesis) to that foo function definition.
Now, when that function gets called foo(1,2), first a new execution context gets created inside the global execution for that foo function. You can imagine this as a box abstracted inside. The arguments 1 and 2 gets mapped with the 'a' and 'b' parameters of the function as variables inside the foo execution context and not the global execution context. Then, the function just returns the value of a+b to the global execution context through the call stack.
Okay, so to check this, if you would have just called the function and then after that defined it like below
foo(1,2);
function foo(a,b){
return a + b;
}
You would probably get an error since the foo function definition is not present in the global execution context and would basically result into a REFERENCE ERROR.
Now, talking about the parameters itself, whether they get hoisted or not. Then No! Those are itself created when the function gets called and a new execution context is created. These variables are block scoped to the function and are not visible to the outer/global execution context. So as and when the function gets returned to the callee, the variable inside of it are just garbage collected.
Hope that answers your question.

How are self-invoking functions hoisted?

Please see this code example:
var myFunc = function () {
alert("hello world");
})();
This is a function expression, which is not hoisted. So my presumption here is that it runs only when the code gets to its actual position within the code. Is this true?
This is a function expression, which is not hoisted.
Yes. Function expressions are not hoisted (self-invoking or otherwise).
What's more, there are no references to the function stored anywhere, so there isn't anything to hoist in the first place.
So my presumption here is that it runs only…
Function declarations are hoisted, but that has nothing to do with when they are run. Just when the variable name matching the function name gets it's value (so it can be used to call the function).
A function only runs when it is called.
In your code, then is when the () after the function body are processed.
The var declaration of myFunc, like all var declarations, will be hosted. It will get an initial value of undefined and then, when the function runs, it will get the return value (also undefined) of that function.
Yes you are correct.
Function expressions in JavaScript are not hoisted, unlike function declarations. You can't use function expressions before you define them
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function

Is a function hoisted if it is defined within an if condition?

So suppose I have something like this
var x = 1;
if (function f(){}) {
x += typeof f;
}
x;
This outputs "1undefined". I thought it should have output "1function", because function f(){} should have been hoisted above the if. This is clearly not the case - why? I thought function declarations and bodies were always hoisted to the top of the scope?
Function declarations are hoisted. Function expressions are not.
This creates a named function expression:
if(function f(){})
It doesn't do anything except check to see if the function expression is truthy. (Function expressions are always truthy.)
Regarding named function expressions, see https://kangax.github.io/nfe/#named-expr:
An important detail to remember is that this name is only available in
the scope of a newly-defined function
This code is outside the scope of the new function expression, and therefore f is undefined:
x += typeof f;
Within a named function expression, you can refer to its name without a problem:
(function f() {
alert(typeof f); //function
})();
alert(typeof f); //undefined
As far as I know ES5 does not define the behavior for function declarations inside blocks.
Quoting Kangax:
FunctionDeclarations are only allowed to appear in Program or
FunctionBody. Syntactically, they can not appear in Block ({ ... }) —
such as that of if, while or for statements. This is because Blocks
can only contain Statements, not SourceElements, which
FunctionDeclaration is. If we look at production rules carefully, we
can see that the only way Expression is allowed directly within Block
is when it is part of ExpressionStatement. However,
ExpressionStatement is explicitly defined to not begin with "function"
keyword, and this is exactly why FunctionDeclaration cannot appear
directly within a Statement or Block (note that Block is merely a list
of Statements).
Because of these restrictions, whenever function appears directly in a
block (such as in the previous example) it should actually be
considered a syntax error, not function declaration or expression. The
problem is that almost none of the implementations I've seen parse
these functions strictly per rules (exceptions are BESEN and
DMDScript). They interpret them in proprietary ways instead.
Function declarations are statements. The conditional part of an if-statement is an expression, so what you have is a function expression; it cannot be a function declaration. And so it isn't hoisted, since only function declarations are.

Function in Scope Before Declaration

I read in a book about function declaration. The code goes like this.
function outer(){
assert(typeof inner === "function", "inner() in scope before declaration");
function inner(){}
assert(typeof inner === "function", "inner() in scope after declaration");
assert(typeof window.inner === "undefined", "inner() undefined in global space")
}
When the tests are run all the three statements are asserted true, showing that the inner() function existed in scope before its declaration. My concept about javascript is that the script is executed line by line and the functions should be declared before there call.
The question is how can the inner function exist in the scope before its declaration?
My concept about javascript is that the script is executed line by line and the functions should be declared before there call.
That's incorrect. In JavaScript, all function declarations in an execution context are processed upon entry into that execution context, before any step-by-step code is executed. So function declarations within functions are processed upon entry into the function when it gets called, and function declarations at global scope are processed before any global step-by-step code is executed. This is sometimes called "hoisting" (because the function declarations are effectively "hoisted" [lifted] up to the top of the scope they're declared in). (Side note: var is also hoisted, more on my blog: Poor misunderstood var.)
This is distinct from function expressions, which like all expressions, are evaluated in the step-by-step execution of the code.
Here's a function declaration:
function foo() { }
Here are three function expressions, note that in each case, they're used as right-hand values (e.g., they're assigned to a var or property, passed into a function, used in a containing expression, etc.), which is what makes them expressions rather than declarations:
var x = function foo() { };
obj = {
b: function bar() { }
};
doSomethingWith(function() { });
There I've shown two named function expressions and one anonymous function expression. If you're going to be writing code for IE8 and earlier, you may want to steer clear of named function expressions as IE's "JScript" interpreter gets them wrong; more (also my blog): Double take.
Javascript executes a function in two Pass, consider this :
There are two ways that you can use a function
1st: function quack(num){
for(var i=0; i<num ; i++)
{
console.log("quacking")
}
} - this is a function declaration.
2nd: var fly = function(num){
for(var i=0; i<num ; i++)
{
console.log("Flying!!!")
}
} - This is a function expression.
Now in the first pass the javascript looks for function declaration
which is
function quack(num){
for(var i=0; i<num ; i++)
{
console.log("quacking")
}
}
So it assigns quack's reference to a variable
which has the same name as that of the method ie.. quack .
So if you call quack() before you declare it, it works fine.
However in the 2nd pass it looks for function expression which
means you cannot call fly before evaluating it.
I hope this gives a better explanation.

How can you use a function that is defined below its usage?

I always thought that function a(){} is identical to a = function(){};
However, these two snippets behave differently:
a();
function a() {
alert("Booya");
}
Prints Booya.
a();
a = function() {
alert("Booya");
}
Fails with an exception, which makes sense, since a is really not defined when called.
So - what kind of 'magic' lets the first snippet work, even though a() is defined below its point of usage?
This is the difference between function declaration and function expression. This difference described well for example here.
In JavaScript all the declarations are hoisted. Means the variable can be used before it has been declared and function can be used before its declared.
It’s JavaScript’s default behaviour to move all the declarations at top of the current script.
But this feature may lead to bugs in application so we use strict mode directive to avoid bugs. Strict mode does not allow to use variables without declaration.
more info at here
See this article for an explanation: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
Function declarations and variable declarations are always moved ("hoisted") invisibly to the top of their containing scope by the JavaScript interpreter.
No magic, proper coding is required. AFAIK
document is loaded and parsed, functions are 'loaded'. The the script is being executed. So far no problem _a() _ is found.
no function is 'maped'. The script si executed line by line. It tries to call a() and THEN assign function to a global variable a
Functions are defined global. But if you assign a function to a variable, as you do in the second case, the scope rules for variables come into effect: You can not call the function before its variable was defined.

Categories