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.
Related
The below code gives an output of undefined. I was of the impression that all variable and function declarations are hoisted to the top of their scope and so b should now be at the top the scope before calling a(). However, I still get undefined as my output?
a()
var b = 5;
function a() {
console.log(b)
}
You misunderstand how hoisting works. It doesn't hoist the assignment, it only hoists the declaration. Your code is equivalent to the following:
var b; // undefined
function a(){
console.log(b)
}
a();
b = 5;
Yes the variable declaration is hoisted, but the value is not set on b. The code looks like this
var b
function a(){
console.log(b)
}
a()
b = 5;
Hoisting means the variables will be created “at the top” - but it does not change anything about the time the value assignment happens, the b = 5 part still happens when execution reaches the part where it’s written. So if you call a() before that, b exists, but has not gotten any value assigned yet … hence, undefined
You are using a function declaration to create a function. So function declaration is also hoisted so they are being used before declaring.
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();
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:
Surprised that global variable has undefined value in JavaScript
(6 answers)
Closed 8 years ago.
I am new to closure concept of javascript. As i understood, By runtime call object stores reference to arguments, local variables and named parameters of function. With that, i tried to solve below snippet.
function a(){
var o=10;
function b(){
alert(o);
var o=20;
alert(o);
}
alert(o);
b();
}
a();
I expected the answer to be alert of 10, 20, 20, but it comes as 10, undefined, 20. Because b's call object stores reference to all local variables, first alert(o) in b should give 20, but why undefined is coming? Even if in b(), var o is defined at later point of time after alert(o), for that scenario shouldn't it access o from parent scope? Can somebody through some light on it!.
Because b's call object stores reference to all local variables
Yes. Local variables first, then parent scope variables.
first alert(o) in b should give 20, but why undefined is coming?
You've got two o variables here: One in the a scope, and one in the b scope. Due to hoisting, the variable declaration of var o=20 holds for the entire b scope, introducing an o variable (which is initially undefined) into the scope when b() is called.
Maybe this makes more sense:
function a(){
var o; // hoisted
function b(){ // hoisted
var o; // hoisted
alert(o);
o=20;
alert(o);
}
o=10;
alert(o);
b();
}
a();
Btw, you've not yet experienced a closure, whose distinguishing feature is that the parent scopes are persistet with the child function objects, even after the parent function has returned.
Consider the following code.
<!DOCTYPE html>
<script>
console.log(a);
function a() {}
</script>
Notice that a is seemingly accessed before it is defined. The console output is: (jsfiddle)
function a() {}
Function and variable names are defined before any other code runs, so the console.log call works here. This is called hoisting.
But this doesn't work if the function is defined as a parameters in a function call. Look at this code.
<!DOCTYPE html>
<script>
function a() {}
a(function b() {});
console.log(b);
</script>
Notice that the function b is defined inside of a call to a. Not inside of a closure, but inside of a call. The console output is: (jsfiddle)
Uncaught ReferenceError: b is not defined
I'm wondering why this happens. Is this the intended behavior? This happens in both Chrome and Firefox.
UPDATE: This jsfiddle shows that names in function expressions are never available in the scope in which they are defined. However, the name is defined inside the scope of the function itself. This means a named function expression can refer to the name, but only inside the function. The name is also stored in the function's name parameter.
<!DOCTYPE html>
<script>
console.log(a); // undefined
var a = function b() {
console.log(b); // function b() { … };
};
a(); // function b() { … };
console.log(a); // function b() { … };
console.log(a.name); // b
console.log(b); // Uncaught ReferenceError: b is not defined
</script>
Inside a(function b() {});, the function is a function expression and not a function declaration (only which are hoisted). You might have a look at var functionName = function() {} vs function functionName() {} for the difference.
EcmaScript §13 (see the paragraph below the NOTE) defines how Function Expressions and Function Declarations are handled.
Function Declarations are instantiated when the EnvironmentRecord is built (§10.5) and thus hoisted, a Function Expression is evaluated later and it's optional Identifier is never visible to the enclosing scope.
As this is a function expression, it's name is not visible to the outer scope. It's the same like
a = function(){}; // valid as it is a function expression
a = function b(){};// also valid
// b is is not accessable here, same as the anonymous function, but a of course is.
both are valid, but b is not visible to the outer scope. Omitting the name in a function declaration however is not valid.
The optional Identifier of the function expression is for reference purposes inside the function body (e.g. to enable recursive calls).
Update to your Update:
The reason why the first console.log yields undefined instead of throwing an error is the hoisting (While the instantiation is hoisted the initialisation isn't):
console.log(a); // undefined
var a = function b() {};
console.log(a); // function b() {}
// equals (hoisted):
var a;
console.log(a); // undefined
a = function b() {};
console.log(a); // function b() {}
function b() doesn't exist until the call a(function b() {}); is executed.
JS doesn't search the code for functions, that way. Also, function b() {} isn't a function declaration, you're merely passing it as a parameter. The only way to access that function would be within function a():
function a() {console.log(arguments[0])}
a(function b() {});
//function b() {}
However, this does not mean that you can actually call b() inside a(), since b() is defined in the scope of a's function call, not in the function itself. Basically, the name b is useless.