Does this line contain a function declaration? - javascript

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.

Related

Does JavaScript have expression-scope?

The following code demonstrates an immediately invoked function expression used as the right-hand value for a default value in a destructuring assignment expression.
const { foo = (function bar() { return 'bam'; }()) } = {};
Function expression bar is not visible outside of the expression.
Does this mean JavaScript has expression scope?
If so, does this mean that the expression has its own conceptual LexicalEnvironment?
The function expression bar is not visible because it's a function expression, even if a named one. It does not create any symbol for that function in the symbol table.
function bar() {}
This is a function declaration which creates a symbol bar.
(function bar() {});
This is a function expression which does not result in anything. It's a named function expression so you'd see a function name pop up in stack traces and the function can refer to itself by name, but it's not a function declaration.
Yes and yes.
The official spec for JavaScript even has a section talking about lexical environments.
At a high level, basically any closure or block will define a new level of scope, where functions aren't available outside of them. This is used to help provide scoping and do things like emulate "private" variables.

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.

Do var fn = function() {...} and var fn = function foo() {...} ever differ?

When you're assigning a function to a variable, does it make any difference at all if you use a named instead of an anonymous function. The following generates an error that "foo() is not defined".
var fn = function foo(){...};
foo();
Can anyone clear up what's going on here?
You're creating a named function expression.
Except in IE, the name is only visible inside the function.
In your example, the variable fn is accessible in the current scope, but foo is only accessible in the functions scope. For example:
var bar = function foo() {
document.write("Internally, Foo is " + typeof foo + "<br/>");
document.write("Internally, Bar is " + typeof bar + "<br/>");
};
document.write("Foo is " + typeof foo + "<br/>");
document.write("Bar is " + typeof bar + "<br/>");
bar();
Will produce:
Foo is undefined
Bar is function
Internally, Foo is function
Internally, Bar is function
http://jsfiddle.net/robert/TEnjb/
Because it (foo) is not defined ;-)
In this context, function is a function-expression ("FunctionExpression") and not a function-statement ("FunctionDeclaration") -- there are two different productions in the grammar. Only the function-statement form [magically] assigns (and hoists the assignment) of the function name to the appropriate variable. Even functions created with a function-expression can have a name, it just happens to be optional, but there is no implicit assignment as with the other form.
[Edit: Apparently this is more quirky then I imagined. In any case, the above cases hold for a properly conforming browser. For instance Gecko has the "function statement extension, which is non-conforming, and IE/JScript exhibits different behavior, which is also non-conforming. Both of these are incorrect implementations according to the grammar specification.]
Consider the following, which should hopefully show why a ([more] conforming implementation) will sanely throw an exception:
// `function` is just an expression here -- there is no good reason for it to
// cause an implicit side-effect. And, according to the specification, it will not.
(function foo () {}).name // "foo", at least in FF
foo // undefined
On a side note: Any function production which is not a top-level statement or a statement directly inside a function block is a function-expression. The behavior of the following is quirky across browsers:
foo() // works in IE (this should never work)
if (true) {
// this is an INVALID GRAMMAR production, although it is accepted in browsers,
// with different operational semantics
function foo () {
}
}
foo() // works in FF and IE (this should never work)
Happy coding.
A little trip to the ECMAScript specification to talk about the grammar. The "rules" can be equally found there, although I find Ed. 5 to be written in the most confusing manner possible. (It misses for forest for all the trees...)
Grammar for FunctionExpression:
// There is a silly long expression tree to get here.
// Look it up if you want :)
FunctionExpression : function Identifier [optional] ( FormalParameterListopt ) { FunctionBody }
Grammar for FunctionDeclaration (what I refer to as a function-statement above), and associated "chain":
FunctionBody : SourceElements [optional]
Program : SourceElements [optional]
SourceElements : SourceElement
SourceElements SourceElement
SourceElement : Statement
FunctionDeclaration
FunctionDeclaration : function Identifier ( FormalParameterListopt ) { FunctionBody }
Note that there is no grammar rule for the "INVALID GRAMMAR" noted. The only way to get to a FunctionDeclaration is through a SourceElement which is only valid inside a FunctionBody or Program (which does not include other blocks like if). "Normal expressions", as a FunctionExpression are restricted, as per below:
An ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous with a Block. Also, an ExpressionStatement cannot start with the function keyword because that might make it ambiguous with a FunctionDeclaration.
...and an apt note from the spec:
Several widely used implementations of ECMAScript are known to support the use of FunctionDeclaration as a Statement. However there are significant and irreconcilable variations among the implementations in the semantics applied to such FunctionDeclarations. Because of these irreconcilable difference, the use of a FunctionDeclaration as a Statement results in code that is not reliably portable among implementations.
Technically, fn is a function pointer pointing to "foo", but you don't really see this in Javascript. You should really just write:
function foo() {
/* ... */
}
foo();
As others have pointed out, your assignment makes the foo function "live" only in the scope of fn, so when fn goes out of scope, the function object could in principle be cleaned up. If you have a really compelling reason to do that then use the function pointer, but otherwise you can just keep the function global.
On some versions of IE this will work, but only because they are non-conforming.
var fn // declares a variable named fn
= function // initializes fn
foo // declares a name foo that is only visible within the function body.
(){
... // foo is visible here.
};
foo(); // foo is not defined here (except on IE 6 and earlier)
fn(); // works just fine.
Note also that although it's often said that:
function foo() {
};
is just syntactic sugar for:
var foo = function() {
};
it's actually not quite true.
In the former case the named function is immediately available when the script is parsed regardless of the order of definitions in the file.
In the latter, the anonymous function body is parsed immediately, but its assignment to a locally scoped variable doesn't happen until that line of code is executed. This means that you can't call foo() in any code executed before then.
Depending on the scope and how you define the function it can be a Function Declaration, Function Expression, or Function Statement. These three function types are treated and loaded differently. Among them, only function declarations require a name. So two other types can be defined without a name. These three types are also different in they way they are assigned to a variable with the function name.
Function Declaration : is defined in the top scope and is not used in another expression/statement (e.g., it is not assigned to a variable)
function foo(){}
The function object is assigned to the variable foo in the global scope.
Function Expression : is defined in another expression/statement.
var bar = function foo(){}
The function object is assigned to the variable foo but in the inner scope (i.e., the scope inside the function)
Function Statement : they are allowed to be anywhere where plain Statements are allowed.
if (true) {
function foo(){ }
}
The function object is assigned to the variable foo in the outer scope (i.e., the scope contains the function definition).
For more information look at this address: http://kangax.github.com/nfe/

What's This Syntax All About?

These are the first few lines in the MicrosoftAjax.debug.js file.
What are they doing with the syntax? Specifically line 3.
Function.__typeName = 'Function';
Function.__class = true;
Function.createCallback = function Function$createCallback(method, context) {
This is ordinary code which happens to have a $ character in a function name.
The expression function Function$createCallback(method, context) { ... } is a named function expression; it evaluates to a function named Function$createCallback.
Unlike many languages, the $ character is perfectly legal in a Javascript identifier (see jQuery), so this is a normal function with a somewhat unusual name.
The code assigns that function to create a createCallback property on the Function object.
(The property happens to be a function; Javascript functions are no different from variables)

A simple question about Javascript functions, differences in invocation/definition

Can someone please explain the difference between the following function definitions?
var alertMessage = function alertMessage(message) {
alert(message);
}
var alertMessage = function(message) {
alert(message);
}
What are the implications of each? Thanks!
Both are function expressions, basically the difference is that the first is named, and the second one is anonymous.
For example:
var test = function test(message) {
alert(message);
};
var test1 = function(message) {
alert(message);
};
test.name; // "test"
test1.name // "" or "anonymous"
Note: The name property of function objects exist on some implementations, but it's non-standard.
Also, the name of function expressions it's useful for debugging, as you can inspect the call stack to see where you are.
This identifier is only accessible from inside the FunctionBody itself:
(function foo(){
typeof foo; // "function"
})();
typeof foo; // "undefined"
However there is a bug on the JScript implementation (in all versions of IE), which this name is leaked to its enclosing scope.
Both definitions are function expressions, as opposed to function declarations, or functions created by the Function constructor. They both assign a function to the variable alertMessage. The difference is that the first function is named, while the second is anonymous.
Named functions are usually used in function declarations, eg
function alertMessage(message) { ... }
In that case, the function declaration creates a variable in the current scope called alertMessage that references that function. Function declarations are hoisted to the top of the current scope, so you can call declared functions before they're defined in you js file.
A named function used in a function expression (such as the original question) does not create this variable, or get hoisted to the top of the execution scope, so by convention most function expressions are anonymous. The only benefits to naming a function expression are that the name variable is bound within the function (although as CMS mentions, this is implementation dependent) and the function name is output from the function's toString method. This can be useful during debugging (rather than having Firebug output (?) for a huge list of anonymous function calls).
Much more detail at MDC

Categories