This question already has answers here:
What are the precise semantics of block-level functions in ES6?
(2 answers)
Closed 4 years ago.
This is the example:
function b() {
console.log(f);
{
function f() {}
}
}
b()
I thought it would become:
function b() {
// hoist to function scope
function f() {}
console.log(f); // should output function f
}
or
function b() {
console.log(f); // should output reference error
{
// just hoist to block scope like this
function f() {}
}
}
but it outputs undefined, like var hoisting. why?
{} creates block scope so
JS engine will interpret your code something like this
function b() {
console.log(f);
{
var f = function f() {};
}
}
b();
So because of block scoping value of f is not available out of block. and since it is defined as var it is hoisted to parent's scope ( function b's scope ) and turns out to be undefined
If you remove {} .
function b() {
console.log(f);
function f() {}
}
b()
It's due to Hoisting. The function f() {} is inside a block, therefore console.log(f) cannot access the function f() {}, that is out of the scope. However, if you keep the console.log(f) inside the block {}. Hoisting should work.
Related
Here I have two function declarations with same name.
function a() {
console.log('a1')
}
function a() {
console.log('a2')
}
a();
It make senses that a() prints a2.
And here are a function declarations and a function expression.
b = function() {
console.log('b1')
}
function b() {
console.log('b2')
}
b();
But here b() prints b1, what is the reason?
function b() will hoist the definition to the top of the containing scope. As a result, it is declared first. Following that, b is then assigned to with your b = function assignment, and when you call b() it then logs 'b1'.
I think this is the cause of hoisting. because hoisting moves all declarations to the top of the current scope (to the top of the current script or the current function).
and here the function assign to **b for hoisting.**
I have an inner function that references a variable initialized by its containing outer function:
function outer() {
function inner() {
if (foo) { ... }
}
let foo = 'bar';
inner(); // no error
};
However, there are some circumstances where the inner function may be invoked before the statement defining foo has executed. In this case, any reference to foo causes a ReferenceError in the inner function:
function outer() {
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};
This is surprising to me, given that foo has block scope, and I am within the enclosing block when executing the inner function.
More surprisingly is that even attempting to detect this situation with the typeof operator - which I always understood to be a safe way to test for undefined variables - causes the same ReferenceError:
function outer() {
function inner() {
if (typeof foo !== 'undefined') { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};
Edit: I now understand that this behavior is the result of the "temporal dead zone" involving let and const variables discussed elsewhere. However, I'm still looking for a clean, safe way to handle the situation.
Is there any safe way to test whether a block-scoped variable (e.g., one created with 'let' or 'const') has yet reached its declaration?
One brute-force approach is to simply catch the exception thrown by typeof in the "temporal dead zone" before foo has been initialized:
function outer() {
function inner() {
let fooExists = false;
try { fooExists = typeof foo !== 'undefined' } catch(e) {}
if (fooExists) { /* ... */ }
}
inner(); // no error
let foo = 'bar';
}
It is also possible to use var instead of let to work around this issue. Because var is function-scoped, the declaration will be hoisted to the top of outer, making the variable available (though undefined) at all times outer is executing:
function outer() {
// due to hoisting, there is a logical `var foo;` here
function inner() {
if (typeof foo !== 'undefined') { /* ... */ }
}
inner(); // no error; `foo` has been hoisted
var foo = 'bar';
}
A similar approach could be taken by putting the declaration (but not initialization) of foo at the top of the outer function while still using let:
function outer() {
let foo;
function inner() {
if (typeof foo !== 'undefined') { /* ... */ }
}
inner(); // no error
foo = 'bar';
}
This last solution would seem to be the cleanest solution for the example given in the question. Unfortunately, it cannot be used when using const variables.
function outer() {
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};
This is surprising to me, given that foo has block scope, and I am
within the enclosing block when executing the inner function.
Because of hoisting, the declaration for foo is hoisted to the top of the block, but not the initialization of the variable. It executes as if you had written:
function outer() {
let foo; // declaration only, so still undefined value
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
foo = 'bar'; // Not initialized until after you call inner!
};
Simply move the initialization up in the block and it will work:
function outer() {
let foo = 'bar'; // declared and initialized
function inner() {
if (foo) { ... } // works as expected
}
inner();
};
I understanding how hoisting in javascript occurs, functions are hoisted before variables, and only the declarations are hoisted. But When I came across hoisting inside if/else conditionals, like this one:
foo(); // "b is the output"
var a = true;
if (a) {
function foo() { console.log("a"); }
}
else {
function foo() { console.log("b"); }
}
Now the conditional is true, so according to the if block, a should have been the output, but due to some kind of hoisting I assume b is the output.
So how is b the output?
In JavaScript, variables, function expressions and function declarations are hoisted to the top of the scope.
Function declarations defines a named function variable without requiring variable assignment.
And important to know is that the entire body of the function declaration gets hoisted up the scope.
E.g.
function outerFunction() {
console.log(typeof functionDeclaration); // outputs "function"
function functionDeclaration() {
// ... function body
}
}
This is because, because of hoisting the code runs like so:
function outerFunction() {
function functionDeclaration() {
// ... function body
}
console.log(typeof functionDeclaration); // outputs "function"
}
In your case, the last function declaration for foo is hoisted to the top of the scope overriding all the other function declarations. Therefore, it logs "b".
Variables and function expressions, however, get hoisted without their assigned values.
E.g.
function outerFunction() {
console.log(functionExpression); // outputs "undefined"
var functionExpression = function () {
// ... function body
}
}
Runs more like so,
function outerFunction() {
var functionExpression = undefined;
console.log(functionExpression); // outputs "undefined"
functionExpression = function () {
// ... function body
}
}
(Ignoring the slightly dodgy behaviour that certain old browsers may have had:)
In Javascript, function statements are scoped within the containing function (or globally if there is no containing function), they're not scoped within an if or else or loop block. So you can't declare a function conditionally in that manner (it can be done another way; see below). And if you declare more than one function with the same name in the same scope the later one will overwrite the first one.
So what happens with your code is:
Both function statements are hoisted, but
They both have the same name so the first is overwritten by the second.
The variable, a is created but not yet assigned a value.
The foo() statement is executed, logging "b"
a is assigned the value true.
The if is executed. The condition is true, but neither the if nor else branches actually do anything because they don't contain statements other than the function declarations that were hoisted earlier.
If you want to create functions conditionally you have to declare a variable and then assign a function expression to it. And then you can not call the function until after that assignment:
var foo;
var a = true;
if(a)
foo = function() { console.log("a"); };
else
foo = function() { console.log("b"); };
foo();
The is not the correct behavior anymore in modern JS browsers! The modern browsers will compile and hoist the mentioned code like this:
// hoisting (treat foo declarations as a normal variable declaration inside if statement)
var a;
var foo;
// now the assignment
foo(); // TypeError (foo = undefined)
a = true;
if (a) {
function foo() { console.log("a"); }
}
else {
function foo() { console.log("b"); }
}
This is a unspecified behavior, different browser behaves diffrently.
MDN explain
In chrome & firefox, it will output foo is not a function.
And in safari, it will output b.
another doc of MDN
I'm playing with closure and have no problem understanding how inner functions have access to outer lexical environments:
function outer() {
var bar = 0;
function inner() {
console.log(bar);
}
inner();
}
outer(); // prints '0'
But what gets me is this:
function foo() {
return function inner() {
console.log(bar);
}
}
function outer() {
var bar = 0;
var fakeInner= foo(); // not the same as "var fakeInner= function () { console.log(bar); }"
fakeInner();
}
outer(); // ReferenceError: bar is not defined
Here I try to "define" an "inner function" fakeInner by assigning it to a function expression returned from an outside function.
I used to think that JavaScript creates the fakeInner inside with a "copy" of its code, something like: var fakeInner= function () { console.log(bar); }, which would then have access to bar, but this is not the case -- it appears when fakeInner is invoked, JavaScript traces back to its definition. Am I understanding this correctly? That is, function objects (either declarations or expressions) are mere references to their definition spots, and passing them do not change their lexical environments (hence inner functions have to be defined inside with explicit syntax)?
Yes, functions do only have access to their own lexical environment - from where they were defined. JavaScript does not have dynamic scope where a function has any kind of access to the scope where it is called.
This happens by attaching the scope to the function object, it is a part of the closure.
In this example,
function outer() {
var bar = 0;
function inner() {
console.log(bar);
}
inner();
}
outer();
scope of bar is outer function and will be available for all function defined in it.
function foo() {
return function inner() {
console.log(bar);
}
}
function outer() {
var bar = 0;
var fakeInner = foo(); // not the same as "var fakeInner= function () { console.log(bar); }"
fakeInner();
}
outer();
In this example, again bar is accessible inside outer but foo is outside it. Hence reference error is thrown.
Also refer What is the scope of variables in JavaScript? for more information.
The scope of inner functions is its own outer function. Not the function it is being called from.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
JavaScript: var functionName = function() {} vs function functionName() {}
What is the difference between those two functions
function a()
{
b=2;
alert(b);
}
a();
and this function
var a=function()
{
b=2
alert(b);
}
a();
what is the main difference
The main difference is that when you declare function:
function a(){
// something...
}
it becomes accessible in the same scope even before the place in the code where it is declared.
But when you assign anonymous function to a variable:
var a = function(){
// something...
};
it is not available before the assignement.
When the functions are created
It is a result of when the function is actually created. In first case it is created when the code is compiled, while in the second case the function is created when the interpreter reaches the line of assignment.
Test code
You can see the difference I mentioned above by executing the following code (jsfiddle):
try {
a();
} catch(e) {
alert('problem calling function a(): ' + e);
};
try {
b();
} catch(e) {
alert('problem calling function b(): ' + e);
};
function a(){
alert('function a() called');
};
var b = function(){
alert('function b() called');
};
You will see (as in mentioned jsfiddle), that a() function is called properly even before the actual declaration, but b() is not available before the assignment.
The only real difference is that the second function has no name, and that the function a() {} one is hoisted.
The difference is that function a() is defined at parse-time for a script block while var a=function() is defined at run-time.
<script type="text/javascript">
// No errors occured;
function a();
function a(){
console.log("Success");
}
</script>
<script type="text/javascript">
// An error will occured;
a();
var a = function (){
console.log("Success");
}
</script>