Does JavaScript have expression-scope? - javascript

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.

Related

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.

Why a Name Function Expression not available outside function body [duplicate]

This question already has answers here:
Javascript functions like "var foo = function bar() ..."?
(9 answers)
Closed 6 years ago.
The Named Function Expression which is defined as
var ninja = function myNinja();
has a behavior which is not able to get through my head.
Have a look at the below code
var ninja = function myNinja() {
console.log(typeof myNinja) //prints 'function'
};
console.log(typeof myNinja) //prints 'undefined'
Now, myNinja is a named function and as far as I know javascript allow the named function to go beyond the scope of its own function.
This is creating confusion in my head.
No, the function is not a named function, it's a function expression.
A function expression can optionally have a name. Ref:
function [name]([param1[, param2[, ..., paramN]]]) {
statements
}
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function
About the function name:
name
The function name. Can be omitted, in which case the function
is anonymous. The name is only local to the function body.
(Emphasis mine.)
A named function has a very similar syntax, but it's a declaration, not an expression.
Now, myNinja is a named function and as far as I know javascript allow the named function to go beyond the scope of its own function.
Only in a function declaration. It's specifically not the case for a named function expression. It's just how this is defined in the specification.
All the gory details are in the spec, the most relevant bit is:
NOTE The Identifier in a FunctionExpression can be referenced from inside the FunctionExpression's FunctionBody to allow the function to call itself recursively. However, unlike in a FunctionDeclaration, the Identifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression.
So if you changed your code to:
function myNinja() {
console.log(typeof myNinja) //prints 'function'
}
var ninja = myNinja;
console.log(typeof myNinja) //prints 'function' (now we're using a declaration)
...since that uses a function declaration, myNinja is added to the scope in which it's defined. (The declaration is also hoisted, like all declarations; it's not processed as part of the step-by-step code the way expressions are.)
Your function is being stored in the variable ninja, so you can't access it by the function name, only the variable name:
console.log(typeof ninja)
This differs from a function declaration like below, which in contrast can be accessed by the function name:
function ninja(){
}
There are other differences, such as the latter being 'hoisted', unlike the former.

where in javascript is this kind of function assignment to variable useful?

I am reading the book. Javascript, The good parts by Douglas Crokford. There are examples provided in the book, but I am not able to understand where and how such examples could be useful in practice. I have modified the code here for simplicity.
here are two ways, I can do function assignment to a variable.
example1:
var test= function(ex) {
alert(ex);
};
test(5);
this produces alert box with value of 5
example2:
var test1 = function test2(ex) {
alert(ex);
};
test1(7); //this produces alert box with value of 7
test2(8)//this does not give a alert box
I have defined function test2 but assigned it to test1. why can't I access test2 directly by calling test2(8).
Further I do not see any big advantage in example 2 over example 1. If you there is some difference, and one of them is superior, I would like to hear that.
Thanks
var test1 = function test2(ex) {
console.log(test2);
};
Naming the function gives it the ability to reference itself from within its body.
test2 is visible only to test2 and its child scopes (functions) if any.
You're basically assigning a function with a name to test1, what's called a "named function expression". It's useful to debug your code because the name of the function will appear in the call stack trace rather than "anonymous function".
Functions in JavaScript are objects too, so the identifier for the function is test1 (the function object), but the function itself has a name of test2, so test1.name == 'test2'
The syntax you're referring to is called a named function expression. It is primarily used to support recursion in anonymous functions.
In javascript prior to ECMASCRIPT 5, there are two ways to do recursion when the function is anonymous.
Using arguments.callee:
(function(x){
alert(x);
if (x) {
arguments.callee(x-1);
}
})(10);
Using a named function expression:
(function countdown (x){
alert(x);
if (x) {
countdown(x-1);
}
})(10);
In ECMASCRIPT 5, when strict mode is enabled arguments.callee is no longer supported. Therefore, in ECMASCRIPT 5 strict mode and for future versions of javascript you should use named function expressions to write recursive anonymous function.
Additional answer:
Now you may be wondering, that's not the syntax you're asking about. That syntax looks like:
(function foo () { foo })()
and you were asking about:
var bar = function foo () { foo }
Actually, they're the same. The named function expression syntax applies to function expressions. Which is nothing more than functions declared in expression context.
In javascript, expression context is simply anywhere math is evaluated. Basically, expression context is anything between braces (), anything to the right of the = sign. And anything which needs to be evaluated by an operator.
Apart from the two forms above, the following are also valid named function expressions:
!function foo(){ foo };
0==function foo(){ foo };
0?0:function foo(){ foo };
The way you want it to behave is against the specification. Function declarations must be named, and their name represent variables in the current scope. But function expressions, when named, should not create a variable with their name. Instead, their name becomes available only inside the function.
Some old browsers (e.g. IE8) used to leak the names as variables, see Named function expressions demystified.
Your example 2 is not really an example of proper JavaScript. There are two ways to define a function:
var foo = function(x) { console.log(x); return x; }
and
function foo(x) { console.log(x); return x; }
note that in the first example you are effectively creating an anonymous function first, and then you attach a name ('foo') to that anonymous function object. In the second example, however, you are creating a named function object 'foo' right away.
Also, if you go to console and define first the test2 the way you did it, and then, after it's defined, enter the line var test1 = test2, then you will have both functions available.
You can see the explanation of the deeper technical difference here in another S/O answer, quite upvoted: var functionName = function() {} vs function functionName() {}

What's the difference between naming a function (as opposed to leaving it anon) and creating a reference to it?

In a comment on another thread I started, someone said this:
#adlwalrus yes. try this: var foo = function bar(){}; console.log(foo); But be aware that bar is only function name (what does it mean I'm not sure exactly myself) and not a reference to it, so you can't call it by doing bar(). And assigning (even named function) is not the same as declaring a function. Hoisting (bumping to top of the scope) only works for declarations, assignment will stay in place. – valentinas 6 hours ago
What purpose does a function name serve if you can't call it with bar()?
For the function to call itself.
var x = function y(val){
if (val){
console.log(val);
y(val-1);
}
};
x(5);
> 3
> 2
> 1
y(3);
> ReferenceError: y is not defined
You're referring to a named function expression. The spec requires that the name of such functions only be available within the scope of the new function. Spec quote:
The Identifier in a FunctionExpression can be referenced from inside
the FunctionExpression's FunctionBody to allow the function to call
itself recursively. However, unlike in a FunctionDeclaration, the
Identifier in a FunctionExpression cannot be referenced from and does
not affect the scope enclosing the FunctionExpression.
On the other hand, the result of that expression is a reference to the new function, which can be saved and referenced anywhere.
Lots of details here:
http://kangax.github.com/nfe/#named-expr
I'd read the whole thing.
As for benefits, another is that it makes them easier to identify in a debugger.
There are two ways to create a function in JavaScript, a "function declaration" and a "function expression." I believe it was Doug Crockford who explained it best when he pointed out that unless "function" is the very first set of characters on a given line, you're performing a function expression (not a declaration).
Function declarations are finicky creatures. You'll recognize them when you see them. They look like this:
function foo() { /* ... */ }
They're always given a name (it's requited) and the name is locally scoped to the lexical context under which the function is declared. So if you perform a function declaration in the global context, then the function can be referenced via it's name globally. If you do it within a function, the function's name can be referenced only within that function and any functions declared within that function.
I think the most important aspect of this method of declaring a function (one that is rarely commented on) is that the function initialization gets hoisted to the top of the current lexical context. Therefore, you should never, ever use a function declaration within a conditional, such as this:
//DON'T DO THIS!
if (x) {
function foo() { return 1; }
} else {
function foo() { return 2; }
}
foo(); //will always be 2, regardless of the value of x.
A function expression is slightly different. Often, they're directly assigned to a variable, like so:
var foo = function() { /* ... */ };
This is nearly identical to the function declaration above except that the initialization is not hoisted. So you can do the following:
var foo;
if (x) {
foo = function() { return 1; };
} else {
foo = function() { return 2; };
}
foo(); //will be 1 or 2, depending on the truthy-ness of x.
So, back to the original question. Function expressions can also have a name, though it's not required and it's not scoped to the context in which the function is declared (as with function declarations). Instead, it gets scoped to the function's own lexical context. This is very useful in some cases. My personal favorite is this pattern:
(function foo() {
//Do something.
setTimeout(foo, 1000);
}());
foo; //undefined
Because of the parenthesis before the word "function", this is a function expression and the name is scoped internally only. But that's okay, because we only need to call it internally (via setTimeout()). The result is that the function will execute once immediately, then will re-execute every second or so after it's finishes execution. This is safer than using setInterval() because it will wait until it's done executing before rescheduling itself, preventing overlaps that could cause missed executions and/or "domination" of the JavaScript thread.
Essentially, the use of a named function expression is limited, but when you need it, it's very powerful.

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