This question already has an answer here:
Why can’t I assign values to a variable inside a named function expression with the same name?
(1 answer)
Closed 5 years ago.
I got an unexpected result. Here's the code:
b = function c() {
console.log(c);
c = 3;
console.log(c);
}
b();
I thought the second console.log should print "3" but instead I got the function itself. Why?
Meanwhile, from the code below I got the right "3".
function ff() {
ff = 3;
console.log(ff);
}
ff();
You cannot overwrite the function's named variable inside its own declaration.
NFE (Named Function Expression) name cannot be overwritten (because it is constant)
This is clear when you write in strict JS mode. Try the example below:
'use strict';
var b = function c(){
console.log(c);
c = 3; // c still is a function
console.log(c);
}
b();
You are using a function expression:
FunctionExpression :
function Identifieropt ( FormalParameterListopt
) { FunctionBody }
So b = function c() { ... }; is perfectly valid, strict mode or otherwise. What happens to c is another question. According to the specs:
The production
FunctionExpression : function Identifier (
FormalParameterListopt ) { FunctionBody }
is evaluated as follows:
[...]
3. Call the CreateImmutableBinding concrete method of envRec
passing the String value of Identifier as the argument.
4. Let closure be the result of creating a new Function object
as specified in 13.2 [...]
5. Call the InitializeImmutableBinding concrete method of envRec
passing the String value of Identifier and closure as the arguments.
[...]
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:
c is visible inside the function but not outside it
c cannot be overwritten from inside the function (an "immutable" binding)
Meanwhile, from the code below I got the right "3".
function ff() {
This is a function declaration; different (and more obvious) rules apply here.
This pattern of function declaration shown in the first example is called NFE (named function expression), while the othher one is called function declaration. The big difference is, in case of NFE, the function's name, i.e. c in our case lives only incide the scope of the function. Therefore, if you will try to call it by its' name from outside wou will get the error, c is not defined, which means c doesn't exist globally.
b = function c(){
console.log(c);
c=3;
console.log(c);
}
c(); //c is not defined
Now look closely at the line c=3 inside the function body of c. What this code block normally would have done, is create a global variable by the name c, outside the function body, which would have been accessible, outside the function as well. But, here, as the c already lives inside the scope of the function's own body, it will not let you declare there, cause it will mean to overwrite its' own name, which is not allowed in case of NFE, (but allowed in case of function declaration, i.e, the second example in question). That is precisely why the assignment code, c=3 is not doing anything here.
To realize it more closely, you can update c=3 with var c=3, in which case it will let you declare a local variable by the name of c inside your function body, which you can then use inside the function.
b = function c(){
console.log(c);
var c=3;
console.log(c);
}
b();
Related
I saw the code below that someone posted. I’m confused about what it logs. It logs the function a, not 200. Why?
var a = 1;
(function a() {
a = 200;
console.log(a)
})()
Because the function being immediately invoked is named, and that name cannot be reassigned to refer to something else directly inside the IIFE.
Any named function expressions will exhibit this behavior as well. A function expression whose function is named a will mean that a directly inside the function will always refer to the function itself, even if you try to reassign it.
You can make the error explicit if you use strict mode:
'use strict';
var a = 1;
(function a() {
a = 200;
console.log(a)
})()
Uncaught TypeError: Assignment to constant variable.
Having a named function expression is a bit like having
(function a() {
const a = <this function>;
// ...
})()
except trying to reassign it will only throw in strict mode.
Specifically, I believe the ECMAScript 5 specification for this behavior is in SetMutableBinding:
If the binding for N in envRec is a mutable binding, change its bound value to V.
Else this must be an attempt to change the value of an immutable binding so if S (strict mode being used) if true throw a TypeError exception.
But directly inside a function, the function name binding is not mutable - see Function Definition:
The production
FunctionExpression : function Identifier ( FormalParameterListopt ) { FunctionBody }
is evaluated as follows:
Call the CreateImmutableBinding concrete method of envRec, passing the String value of Identifier as the argument.
Looking at the hoisting example from this site, I don't get why the below alters 1 even after the hoisting:
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a); // alerts 1
is actually
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
alert(a);
Shouldn't it alter 10 because a is still assigned to 10 before b function returns? Why does calling an empty a function cause this? On a related note, why does the below not alert function but still alter 1? Doesn't a get reassigned to a function with the declaration?
var a = 1;
function a() {}
alert(a);
Let's take it line by line,
Here, b(); you call the function b. What has the function b in its body? The declaration of a new function whose name is a. When you access a inside the b, you actually don't access the global variable a, but the function you just declared. So the 10 will be set to the pointer that points to function called a and not the global variable called a
But why does the first block of code alerts 1? I am confused
Because when the JavaScript engine goes to execute the assignment:
a = 10;
checks where a has been defined. Since in the current scope, where you try to set 10 to a, there is a function declaration, whose name is a, Then will happen that I described above. But you would say why? The function declaration is below the assignment. The reason why this is happening is the fact the JavaScript engine first process the declarations in your script and then proceeds to the execution of your script. So when the engine would questioned about a, where a is defined, as always it will look first at the current scope. If there isn't there then it will look in the scope where the current scope is enclosed. In your case this is the global scope, as I can infer from your code. So if you hand't defined this function, the the second step I mentioned before would have been done and since there is variable called a, would had alter it's value. If there isn't there any variable then a would have been defined on the global scope and it's value would have been 10.
var a = 1;
function b() {
a = 10;
return;
// I renamed the function from a to c to notice the hoisting
function c() {}
}
b();
console.log(a);
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.
Javascript Code
var d = function c() { console.log(c); };
d(); // function c() { console.log(c); };
c(); // Reference Error
I understand the concept of variable hoisting where variable declarations and function definitions are hoisted to top of the existing scope. Also function definition in function expressions are not hoisted.
So, above will be
var d;
d = function c() { console.log(c); };
d();
c();
Hence d is a reference to a named function c
on executing d() the function c is executed in global scope, where there is no variable or property named c. But still console manages to log function definition of c.
When I tried c() I got a reference error. [As I Expected]
Case 2 proves that there is no window property named c available
So, How did d() manage to print the c's definition on execution?
Does every function have its own definition in its local scope as a property?
Yes. A named function expression produces a variable corresponding to the function name within the scope of that function only.
Here's an excellent but lengthy article on the subject: http://kangax.github.com/nfe/
See also the relevant section of the ECMAScript 5 spec. It has a specific note about this.
My question is based on the example from a book "Object Oriented JavaScript" (page 81 - Lexical Scope)
So, i understand from this example ...
function f1(){var a = 1; f2();}
function f2(){return a;}
f1();
... that:
a is not defined
But, how f1 get's to know about f2, which is defined after f1 ?
This behavior raises a question:
How JavaScript interpreter works ?
I assume, that it:
scans the code and simply stores the functions, not assigned to any var, in a global environment
Invokes a function in ad-hoc way: when there is no such a function in a global environment, then complain.
Function declarations are processed upon entry into an executable context (e.g., the global context, or a function call), prior to any of the step-by-step code in the context being processed.
So in your code, these things happen (in this order):
A "variable object" is created for the execution context.
Entries (actually, literally, properties) on the "variable object" are created for every var and function declaration in the context (plus a few other things). In your case, that's f1 and f2. Initially the properties have the value undefined.
All function declarations are processed, and so:
The f1 function is defined and assigned to its property on the variable object.
The f2 function is defined and assigned to its property on the variable object.
The f1(); line is executed, calling the f1 function.
The f1 code refers to f2, which it gets from the variable object, and so it's what we expect it to be (a reference to the f2 function).
The more interesting version is this:
f1();
function f1(){var a = 1; f2();}
function f2(){return a;}
...which happens in exactly the same order listed above, because both of the declarations are handled before the first line of step-by-step code.
Function declarations are different from function expressions, which just like any other expression are evaluated when they're reached in the step-by-step execution of the code. A function expression is any time you create a function and use it as a right-hand value, e.g., assign the result to a variable or pass it into another function. Like this:
var f2 = function() {
};
or this
setTimeout(function() {
alert("Hi there");
}, 1000);
Note that we're using the result of the function statement as the right-hand value (in an assignment, or by passing it into a function). Those are not pre-processed upon entry into an execution context (e.g., not at Step 3 above), they're handled when the flow of code reaches them. Which leads to:
f1();
function f1(){var a = 1; f2();}
var f2 = function(){return a;};
...which fails, because f2 is undefined as of when it's called.
You can use a declared function's value as a right-hand value without turning it into a function expression (we do that all the time), so long as you do it in two separate statements. So:
alert("Beginning");
function foo() { ... }
setTimeout(foo, 100);
That happens in this order:
foo is created (since it's defined by a declaration).
The alert runs.
The setTimeout runs.
(Later) foo is called.
One last point: Although they should work, a function expression that includes a function name does not work reliably on all implementations and must, for now, be avoided:
var f = function foo() { ... }; // <== DON'T DO THIS
Or
setTimeout(function foo() { // <== DON'T DO THIS
}, 1000);
Internet Explorer, in particular, has issues with those, and other implementations have at various times as well.
More to explore:
Poor misunderstood var
Closures are not complicated (because it talks about variable objects and how symbols are resolved)
Anonymouses anonymous (talks more about named function expressions)
you don't have access to variable 'a' inside function f1, because function f2 is not defined inside f1 scope
if you define f2 inside f1:
function f1(){function f2(){return a;} var a = 1; f2();}
f1();
you don't have any problems