I am reading about Function Declarations vs. Function Expressions, and I cannot figure out the meaning of following statement:
Function Declarations occur as standalone constructs and cannot be
nested within non-function blocks.
Someone please to explain with an exemple what does the author means, precisely by: "...cannot be nested within non-function blocks".
Link is: https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
I dont know the author meant it was physically impossible or more of it shouldn't be done. From my understanding what the author was saying is that this:
var y = true;
if (y) {
function example() {
alert('hi');
return true;
}
}
Here the function is declared inside a conditional statement, which is fine since x is true, but if it were false that function would never be declared and when we do want to the call the example function nothing will happen because it was never declared. So it should be
function example() {
"use strict";
return true;
}
var y = true;
if (y) {
example();
}
In the above code we still call the example function if the condition is met, however since example is defined outside the condition statement we can use it regardless of the conditional statement. This Post has more information about it. Hopefully this is what you meant
Taken at face value, the statement:
Function Declarations occur as standalone constructs and cannot be nested within non-function blocks.
is wrong. It's possible to put function declarations inside blocks, as examples in the article show. The reason that it's warned against is that the behaviour differs in different browsers. In most browsers (not certain versions of IE and Firefox), such functions are declared regardless of whether execution enters the block or not, e.g.:
if (false) {
function foo(){}
}
foo is declared and available within the outer scope. This is exactly the same with variable declarations:
if (false) {
var x = 3;
}
In the above, x is declared regardless of whether the block is executed or not. The assignment of the value, however, only occurs if the block is entered.
Back to functions. The reason function declarations in blocks is warned against is that firstly, it infers that the function is only created if the block is entered, which is incorrect for most browsers but not all. Secondly, and more importantly, it's because different browsers have different behaviour.
Some interesting reading:
Richard Cornford: FunctionExpressions and memory consumption
Kangax: Function statements
What are the precise semantics of block-level functions in ES6?
Also note that function statements are warned against in ES5 strict mode and may be introduced in some future version of ECMAScript.
Finally, this behaviour is addressed directly in ECMA-262 ed 6 in Appendix B 3.3.3 and Appendix B 3.4.
I think it means you cannot define functions arbitrarily in the code, see below.
if true {
function funName(){};
}
funName will not be a function in this case, it will cause an error.
Consider the humble if statement:
function whatever() {
// ...
if (something === somethingElse) {
function aFunction() {
// ...
}
// more code ...
}
aFunction(5, 6, 7);
Now, that code is weird. The function is declared inside the if block. But function declarations are hoisted! So what does that mean?
More weird: what if there's a different declaration for "aFunction" in the else clause?
A fundamental aspect of the weirdness from code like that is that function declarations are treated as if they occur at the top of the scope (that is, they're "hoisted"). For that reason, a function declaration inside some other sort of block is just inherently ambiguous and strange.
Note that function instantiation via function expressions are not weird, because those happen as part of running code, like object initialization expressions.
Related
I need some confirmations on what’s happening behind the screen.
There’s an article in MDN that said that we shouldn’t declare functions in a block-level, such as, inside an if-statement. Because it’s inconsistent throughout browsers and anything to do with pre-ES2015 (or pre-ES6).
The function inside the if-statement will not be created unless the condition is true.
I was wondering, IF the condition is true, let’s say 5 minutes later after JavaScript is loaded and set synchronously, will it create the function? Does it still have memory of the code in order to create the function, or is it dumped in unused code and all?
I would like to know whether the function still exists even after the if-statement is completed. Is it accessible? How long is it accessible? Is it accessible until the if-condition is false? Does the result differ from ES6 and pre-ES6? I’ve heard there’s no scope pre-ES6 in if-statements.
e.g.
if (condition) {
function foo() {console.log(“hello world”);
}
}
I was confused after reading an article in MDN on ‘Functions’ under ‘block-level functions in non-strict code’: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
IF the condition is true, let’s say 5 minutes later after JavaScript is loaded and set synchronously, will it create the function?
The function will be created as soon as the if runs, immediately.
Does it still have memory of the code in order to create the function, or is it dumped in unused code and all?
I would like to know whether the function still exists even after the if-statement is completed. Is it accessible? How long is it accessible?
This behavior will be the same regardless of if the function is declared in an if block or not: if nothing can possibly reference the function in the future (for example, if the block ends and nothing inside the block has a reference to the function), it will eventually be garbage collected. The function may still "exist" in memory for a time until the GC runs.
For example, it should be clear that the following function should always continue to exist, at least until you reload the page:
// IIFE, to get off the top level
(() => {
if (true) {
function foo() {
console.log('clicked');
}
window.addEventListener('click', foo);
}
})();
This is because the addEventListener has been passed a reference to the function.
But the following foo function will get GC'd (maybe a second or few after the page is loaded - it depends on the underlying engine, and isn't visible to Javascript):
// IIFE, to get off the top level
(() => {
if (true) {
function foo() {
console.log('clicked');
}
}
})();
If nothing has saved a reference to the function by the time the block that scopes the variable has finished, the function will not be accessible anywhere, and will be GCd.
The rest of the question looks to be essentially the same as: "where can the function be referenced", which is best described in Bergi's answer here. It's a bit complicated, and the behavior differs depending on whether you're using strict mode, the ES version of the environment, and the environment itself (implementations do not always conform to the specification).
For predictable, easy-to-read code, probably best to simply never use function declarations in non-function blocks; only use function declarations when directly inside function blocks.
(Note that function expressions, where the function is used as a value and passed to something or immediately invoked or explicitly assigned to a variable, are not the same as function declarations - function expressions are fine, it's just the weird behavior of function declarations that's problematic. Also note, per comment, that a "function declaration" is sometimes called "function statement".)
I have this code:
function a() {
if(prodotto.approvatoIngredienti==true) {
disegnaIconaIngredienti();
function disegnaIconaIngredienti() {
//
}
}
I defined a function inside another function. With chrome and ie I don't have problem, but firefox gives me this error:
--
[15:26:41.279] disegnaIconaIngredienti is not defined # http://127.0.0.1:8080/Tesi/javascript/InserimentoProdotti.js:1718
Someone can explain me why?
You haven't closed your if statement on the second line.
Your code is equivalent in Firefox to
var disegnaIconaIngredienti;
if (prodotto.approvatoIngredienti==true){
disegnaIconaIngredienti();
disegnaIconaIngredienti = function(){
//
}
}
So the variable doesn't have a value when you call it.
Chrome and Internet Explorer hoist the whole function declaration and not only the variable declaration.
ECMAScript doesn't allow function definition in non function blocks (like your if). Browsers allow it but in different ways.
This related question goes deeper in the topic.
It's because firefox has something called function statements. They're different from typical declarations, and can legally happen in a block.
There's no hoisting of the function itself as you'd find with a declaration, so it needs to be defined before it's used.
Note that in typical ECMAScript, it's invalid to have that style of function inside an if statement, though some browsers allow it. Strict mode absolutely prohibits it.
To have a fully valid function created inside an if, it must be a function that is part of an expression, like an assignment.
function a(){
if(prodotto.approvatoIngredienti == true) {
// legal function in a block
var disegnaIconaIngredienti = function() {
//
};
disegnaIconaIngredienti();
}
You forgot to close the if brace
function a(){
if(prodotto.approvatoIngredienti==true){
disegnaIconaIngredienti();
}
function disegnaIconaIngredienti() {
//
}
}
After further consideration on your closing if and #dystroy's post
I tend to agree with him and say that Firefox doesn't permit using
part of his post to answer :
ECMAScript doesn't allow function definition in non function blocks (like your if). Browsers allow it but in different ways.
Like in your case where Firefox doesn't allow it inside conditional blocks.
What's the meaning of this "Function definitions may not appear within if statements, while loops, or any other statements." I'm quite confuse with this statement.
One issue with what you're reading in the book is that a function definition (which is different than a function assignment) is essentially hoisted to the top of the host function in some browsers so putting it inside a statement (like inside an if statement) is downright misleading. The code will make it look like the function will only be defined if that branch of the if statement executes, but that will not necessarily be the case. So, it's a bad practice. It probably works in many cases, but is a bad practice.
So, rather than this:
function main(foo) {
if (foo) {
function internal() {
// code here
}
// code here
}
}
Put the internal function up at the top;
function main(foo) {
function internal() {
// code here
}
if (foo) {
// code here
}
}
FYI, in strict mode internal function definitions are only allowed at the top. Condition function assignments can always be done with this syntax:
var internal;
if (foo) {
internal = function() {}
}
Many programming languages require a special user-written function that marks the begin
of the execution. For example, in C this function must always have the name main(). In
JavaScript, however, such a function is not required.
What are the logical reason for the absence of such a dedicated top level function in JavaScript? I know this is some kind of theoretical question, but I cannot find an answer online.
Because the entire code block is effectively one big main. In JavaScript, global code can have all of the constructs function code can have, and has stepwise execution, just like functions do. In fact, when the JS engine processes the code block as a whole, it does very nearly the same things that it does when processing a function call. See the specification's sections 10.4.1 ("Entering Global Code") and 10.4.3 ("Entering Function Code") and note how similar they are.
C doesn't allow stepwise code at the global level (you can have all sorts of initializers, and they can get kind of stepwise, but that's a different topic). And so C needs an explicit entry point (main). In JavaScript, the entry point is the beginning of the code.
Regarding your question below about whether global code is sequential. The answer is yes, it's exactly like code in a function that way. So:
var x, y, z;
x = 1;
y = 2;
z = x + y;
alert("z is " + z);
...will alert "z is 3". The code runs sequentially, top to bottom.
There are a couple of things that happen before the stepwise code is executed, though, which is useful to know. The most significant is that any declarations in the source text of the scope being entered are processed before the stepwise code begins. JavaScript has two main types of declarations: Variable declarations, and function declarations:
The name of any variable declared with var is added to the scope (with the value undefined) before any stepwise code is executed. (More: Poor, misunderstood var)
Function declarations are processed and the function names added to the scope before any stepwise code is executed. (JavaScript also has something else, called a function expression, which is stepwise code. More on that below.)
So for instance, in this source text:
var x;
x = 1;
foo();
function foo() {
}
the declarations are
var x;
function foo() {
}
and the stepwise code is
x = 1;
foo();
The declarations are processed first. This is why the call to foo works. (These same rules apply to the source text within functions.) This processing of declarations before anything else is sometimes called "hoisting," because the declarations are in a sense lifted from their location in the source text and moved to the very beginning. I prefer to think of it as two passes through the source: The first pass does declarations, the second executes stepwise code.
(Side note: Declaring a variable more than once in the same scope is perfectly legal [though pointless]. Declaring two functions with the same name is also legal; the latter declaration overrides the earlier one.)
(Side note 2: ES2015 [ES6] introduced let and const variable declarations, which behave somewhat differently from var. You can't declare a variable twice with them, they have block scope, and you can't use the variable prior to the statement where it's declared. So they're mostly not hoisted [there is something slightly like hoisting in that they prevent access to a shadowed variable in a containing scope even before the let x or whatever line].)
More detail, and possibly getting a bit technical:
var
If var happens before the stepwise code is run, you may be wondering about this:
var x = 1;
Does that happen before stepwise code, or as part of it? The answer is that in reality, that's just shorthand for two very different things:
var x;
x = 1;
The var x; part happens before the stepwise code, the x = 1; part is stepwise code and is executed when we reach it in the sequence. So:
alert(x); // "undefined" -- there **is** a variable `x`; it has the value `undefined`
var x = 1;
alert(x); // "1" -- now `x` has the value `1`
Function declarations
JavaScript has two different, but very similar-looking, things: Function declarations, and function expressions. You can tell which is which by whether you're using the resulting function as part of the expression in which it's defined.
Here's a function declaration:
function foo() {
}
These are all function expressions (we use the resulting function value as part of the expression; in computer science terminology, the function is used as a right-hand value):
// 1: Assigning the result to something
var x = function() {
};
// 2: Passing the result into a function
bar(function() {
});
// 3: Calling the function immediately
(function(){
})();
// 4: Also calling the function immediately (parens at end are different)
(function(){
}());
// 5: Also calling the function immediately
!function(){
}();
// 6: Syntax error, the parser needs *something* (parens, an operator like ! or
// + or -, whatever) to know that the `function` keyword is starting an *expression*,
// because otherwise it starts a *declaration* and the parens at the end don't make
// any sense (and function declarations are required to have names).
function(){
}();
The rule is that function declarations are processed before the stepwise code begins. Function expressions, like all other expressions, are processed where they're encountered.
One final side note: This is a named function expression:
var f = function foo() {
};
We use it as a right-hand value, so we know it's an expression; but it has a name like function declarations do. This is perfectly valid and legal JavaScript, and what it's meant to do is create a function with a proper name (foo) as part of the stepwise code. The name of the function is not added to the scope (as it would be if it were a function declaration).
However, you won't see named function expressions in very many places, because JScript (Microsoft's JavaScript engine) gets them horribly and utterly wrong, creating two separate functions at two different times.
JavaScript is event-driven, the program written in JavaScript doesn't have a start and an end. You can compare it to any desktop UI toolkit, where you handle button clicks and key presses, but there is no obvious main once the program is initialized.
For instance there is a window.onload event that is triggered when the page is loaded - and which you can handle.
in a scripting language, the code is executed from the first line in the file to the end as if it was being typed into an interpreter. (this doesn't preclude parsing and compiling the code as long as those process don't effect the denotational semantics described.)
Javascript,python and PHP there are scripting language. These programming languages are not using main() function.
You already know the answer
In JavaScript, however, such a function is not required!
JavaScript is scripting language while C needs to be compiled.
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?