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

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.

Related

Why are parentheses required around JavaScript IIFE? [duplicate]

This question already has answers here:
Explain the encapsulated anonymous function syntax
(10 answers)
Closed 7 years ago.
I'm reading up on JavaScript IIFE and so far the understand concept, but I am wondering about the outside parenthesis. Specifically, why are they required? For example,
(function() {var msg='I love JavaScript'; console.log(msg);}());
works great, but
function() {var msg='I love JavaScript'; console.log(msg);}();
generates a syntax error. Why? There are lots of discussions on IIFE, but I'm not seeing a clear explanation about why the parentheses are required.
There are two ways to create functions in JavaScript (well, 3, but let's ignore new Function()). You can either write a function declaration or write a function expression.
A function declaration in itself is a statement and statements by themselves don't return values (let's also ignore how the debugging console or Node.js REPL print return values of statements). A function expression however is a proper expression and expressions in JavaScript returns values that can be immediately used.
Now, you may have seen people saying that the following is a function expression:
var x = function () {};
It may be tempting to conclude that the syntax:
function () {};
is what makes it an expression. But that's wrong. The syntax above is what makes it an anonymous function. And anonymous functions can either be a declaration or an expression. What makes it an expression is this syntax:
var x = ...
That is, everything to the right of an = sign is an expression. Expressions make it easier to write math formulas in programming languages. So in general everywhere that math is expected to be processed is an expression.
Some of the forms of expressions in JavaScript include:
everything to the right of an = operator
things in braces () that are not function call braces
everything to the right of a math operator (+,-,*,/)
all the arguments to the ternary operator .. ? .. : ..
When you write:
function () {}
it is a declaration and does not return a value (the declared function). Therefore trying to call the non-result is an error.
But when you write:
(function () {})
it is an expression and returns a value (the declared function) which may be used immediately (for example, may be called or may be assigned).
Note the rules for what counts as expressions above. From that it follows that braces are not the only things that you can use to construct an IIFE. Below are valid ways for constructing IIFEs (because we write function expressions):
tmp=function(){}()
+function(){}()
-function(){}()
0/function(){}()
0*function(){}()
0?0:function(){}()
(function(){}())
(function(){})()
You may actually see one of the above non-standard forms (particularly the + version) in third-party libraries, because they want to save one byte. But I strongly advise you to only use the brace forms (either are fine), because they are widely recognized as IIFEs by other programmers.
The version of IIFE that is wrapped in parenthesis works, because this marks the declaration of the internal function declaration as an expression.
http://benalman.com/news/2010/11/immediately-invoked-function-expression/
For more detailed explanation please see:
Advanced JavaScript: Why is this function wrapped in parentheses?
HINT:
The invocation operator (()) only works with expressions, not declarations.
This will be a long-winded answer, but will give you the necessary background. In JavaScript there are two ways functions can be defined:
A function definition (the classical kind)
function foo() {
//why do we always use
}
and then the more obscure type, a function expression
var bar = function() {
//foo and bar
};
In essence the same thing is going on at execution. A function object is created, memory is allocated, and an identifier is bound to the function. The difference is in the syntax. The former is itself a statement which declares a new function, the latter is an expression.
The function expression gives us the ability to insert a function any place where a normal expression would be expected. This lends its way to anonymous functions and callbacks. Take for instance
setTimeout(500, function() {
//for examples
});
Here, the anonymous function will execute whenever setTimeout says so. If we want to execute a function expression immediately, however, we need to ensure the syntax is recognizable as an expression, otherwise we have ambiguity as to whether of not we mean a function expression or statement.
var fourteen = function sumOfSquares() {
var value = 0;
for (var i = 0; i < 4; i++)
value += i * i;
return value;
}();
Here sumOfSquares is immediately invoked because it can be recognized as an expression. fourteen becomes 14 and sumOfSquares is garbage-collected. In your example, the grouping operator () coerces its content into an expression, therefore the function is an expression and can be called immediately as such.
One important thing to note about the difference between my first foo and bar example though is hoisting. If you don't know what that it is, a quick Google search or two should tell you, but the quick and dirty definition is that hoisting is JavaScript's behavior to bring declarations (variables and functions) to the top of a scope. These declarations usually only hoist the identifier but not its initialized value, so the entire scope will be able to see the variable/function before it is assigned a value.
With function definitions this is not the case, here the entire declaration is hoisted and will be visible throughout the containing scope.
console.log("lose your " + function() {
fiz(); //will execute fiz
buzz(); //throws TypeError
function fiz() {
console.log("lose your scoping,");
}
var buzz = function() {
console.log("and win forever");
};
return "sanity";
}()); //prints "lose your scoping, lose your sanity"

Does this line contain a function declaration?

The following line is known as a function expression in JavaScript. Does it contain within it a function declaration?
var foo = function() {};
Edit: edited for clarity.
No, it does not. Both function expressions and function declarations do define functions, and contain the function keyword.
How they differ is basically determined where they appear in the source code, their syntax is otherwise the same. It is
a function expression when it appears where an expression is expected, e.g. within the grouping operator or an assignment expression (as in your code)
a function declaration when it appears directly in the body of a function, module, script (global code), or eval code. Since ES6, declarations can also appear as part of a StatementList, i.e. inside a block.
a function statement when it appears where a statement is expected. Until ES6, this term was used to distinguish it from a declaration when the function syntax appeared in a block. If not inside a block, it is basically equivalent to a declaration.
Also read http://kangax.github.io/nfe/ which explain all these terms (pre-ES6 though).
For the difference between their evaluations see var functionName = function() {} vs function functionName() {}.
We can readily determine that this is not function declaration,
according to ES5 section 14:
Program :
SourceElementsopt
SourceElements :
SourceElement
SourceElements SourceElement
SourceElement :
Statement
FunctionDeclaration
A FunctionDeclaration can only be a SourceElement (a quick search for FunctionDeclaration shows no other grammatical use), and a SourceElement can only be a top-level component of a list of SourceElements (either a Program or a FunctionBody). This use of function is nested inside of an assignment, so it cannot be a top-level SourceElement.
Furthermore, we can also rule out this as a FunctionDeclaration by its definition:
FunctionDeclaration :
function Identifier ( FormalParameterListopt ) { FunctionBody }
Your code does not have an Identifier, which is mandatory for FunctionDefinitions (but optional for FunctionExpressions).
A Function Expression defines a function but does not declare a function. As such the code
var foo = function() {};
defines a function and then assigns it to a variable.
Where as
function foo() {};
defines a function and declares it without the need for an assignment.

Javascript: rounded parentheses surrounding comma separated expressions

Playing on JS console I faced a curious syntax. I wonder if someone can tell me more on that..
Try this:
>( function f(){console.log('i am f')} , (function x(){console.log('i am x')})() , y=2 , console.log('hello') )
i am x
hello
undefined
>f()
ReferenceError: f is not defined
>this.y
2
This will fail:
( var c=2 )
SyntaxError: Unexpected token var
So comma separated expressions inside parentheses are evaluated, assignments happens to be against global scope, but named function declarations references stay trapped inside just like a closure
more...
putting that line inside a function declaration called with new:
function C(){
( function f(){console.log('i am f')} , (function x(){console.log('i am x')})() , y=2 , console.log('hello') )
}
and then instantiating:
>var c=new C()
i am x
hello
undefined
>c.y
undefined
>this.y
2
Happens exactly the same, just as executed in the global scope!
What's the usage / purpose of this construct?
One more:
>( function f(){console.log('i am f')} , f() )
ReferenceError: f is not defined
So the named function can't be referenced neither inside brackets.
The named functions aren't "trapped inside", because they're not function declarations (using function as a statement), they are in fact function expressions (using function as an operator). This means that their names do not become references to themselves in the current namespace.
Certain keyword/tokens can only be used as statements, such as var, hence an error is thrown if you try to use them in conditions which the interpreter expects to be an expression.
As for the y === 2, this is because you did not var y; inside C, so y = 2 sets window.y, and in the global scope this === window.
whats the usage / purpose of this construct?
The comma operator , lets you do multiple expressions on one line.
function expressions are useful for a great many things, be it immediately invoking them so you have a closure, or storing them inside variables, etc.
Wrapping code in parentheses forces it to be parsed as an expression.
The var keyword is only valid as a statement, so this creates a syntax error.
Function declarations can either be statements (which create a hoisted variable) or expressions (which do not create any variable).
Thus, wrapping the function in parentheses turns it into a function expression, which does not create an externally-visible name.
For more information, see here.

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.

whats the difference between function foo(){} and foo = function(){}? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
JavaScript: var functionName = function() {} vs function functionName() {}
are they the same? I've always wondered
No, they're not the same, although they do both result in a function you can call via the symbol foo. One is a function declaration, the other is a function expression. They are evaluated at different times, have different effects on the scope in which they're defined, and are legal in different places.
Quoting my answer to this other question here (edited a bit for relevance), in case the other question were ever removed for some reason (and to save people following the link):
JavaScript has two different but related things: Function declarations, and function expressions. There are marked differences between them:
This is a function declaration:
function foo() {
// ...
}
Function declarations are evaluated upon entry into the enclosing scope, before any step-by-step code is executed. The function's name (foo) is added to the enclosing scope (technically, the variable object for the execution context the function is defined in).
This is a function expression (specifically, an anonymous one, like your quoted code):
var foo = function() {
// ...
};
Function expressions are evaluated as part of the step-by-step code, at the point where they appear (just like any other expression). That one creates a function with no name, which it assigns to the foo variable.
Function expressions can also be named rather than anonymous. A named one looks like this:
var x = function foo() { // Valid, but don't do it; see details below
// ...
};
A named function expression should be valid, according to the spec. It should create a function with the name foo, but not put foo in the enclosing scope, and then assign that function to the x variable (all of this happening when the expression is encountered in the step-by-step code). When I say it shouldn't put foo in the enclosing scope, I mean exactly that:
var x = function foo() {
alert(typeof foo); // alerts "function" (in compliant implementations)
};
alert(typeof foo); // alerts "undefined" (in compliant implementations)
Note how that's different from the way function declarations work (where the function's name is added to the enclosing scope).
Named function expressions work on compliant implementations, but there used to be several bugs in implementations in the wild, most especially Internet Explorer 8 and earlier (and some early versions of Safari). IE8 processes a named function expresssion twice: First as a function declaration (upon entry into the execution context), and then later as a function expression, generating two distinct functions in the process. (Really.)
More here: Double take and here: Named function expressions demystified
NOTE: The below was written in 2011. In 2015, function declarations in control blocks were added to the language as part of ECMAScript 2015. Their semantics vary depending on whether you're in strict or loose mode, and in loose mode if the environment is a web browser. And of course, on whether the environment you're using has correct support for the ES2015 definition for them. (To my surprise, as of this writing in July 2017, Babel doesn't correctly transpile them, either.) Consequently, you can only reliably use function declarations within control-flow structures in specific situations, so it's still probably best, for now, to use function expressions instead.
And finally, another difference between them is where they're legal. A function expression can appear anywhere an expression can appear (which is virtually anywhere). A function declaration can only appear at the top level of its enclosing scope, outside of any control-flow statements. So for instance, this is valid:
function bar(x) {
var foo;
if (x) {
foo = function() { // Function expression...
// Do X
};
}
else {
foo = function() { // ...and therefore legal
// Do Y
};
}
foo();
}
...but this is not, and does not do what it looks like it does on most implementations:
function bar(x) {
if (x) {
function foo() { // Function declaration -- INVALID
// Do X
}
}
else {
function foo() { // INVALID
// Do Y
}
}
foo();
}
And it makes perfect sense: Since the foo function declarations are evaluated upon entry into the bar function, before any step-by-step code is executed, the interpreter has no idea which foo to evaluate. This isn't a problem for expressions since they're done during the control-flow.
Since the syntax is invalid, implementations are free to do what they want. I've never met one that did what I would have expected, which is to throw a syntax error and fail. Instead, nearly all of them just ignore the control flow statements and do what they should do if there are two foo function declarations at the top level (which is use the second one; that's in the spec). So only the second foo is used. Firefox's SpiderMonkey is the standout, it seems to (effectively) convert them into expressions, and so which it uses depends on the value of x. Live example.
I got an excellent explanation on this while asking very similar question: Two functions with the same name in JavaScript - how can this work?

Categories