See this
let foo = 'outer';
function bar(func = x => foo) {
let foo = 'inner';
console.log(func());
}
bar(); //outer
I want to know why the output is 'outer' rather than 'inner'. I know JavaScript has lexical scope. This output makes me feels like that the function x => foo is defined out of function bar
I know js has lexical scope, This output makes me feels like that the function x => foo is defined out of function bar
Not exactly. It's in-betweeen: in the parameter declaration, which has its own scope with access to the other parameters but not the body. The default initialiser basically desugars to
let foo = 'outer';
function bar() {
var func = arguments[0] === undefined ? x => foo : arguments[0];
{
let foo = 'inner';
console.log(func());
}
}
bar(); // outer
This question already has answers here:
Javascript function scoping and hoisting
(18 answers)
Closed 6 years ago.
Hi I am trying to understand the JavaScript fundamentals, and stuck in one condition.
var foo = 1;
function bar(){
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
Here alert(foo), will give me 1, and I know after return statement, function foo() will not execute. But now if change the code:
var foo = 1;
function bar(){
foo = 10;
return;
}
bar();
alert(foo);
In bar function, If I will remove function foo(). then alert(foo) will give me 10
Please help, if someone can explain me why?
This is called Javascript hoisting
I will try to explain it in details.. This is what we have
var foo = 1;
function bar(){
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
The interpreter will rewrite this as
var foo = 1;
function bar(){
function foo(){} // this is also equal to var foo = function(){};
foo = 10;
return;
}
bar();
alert(foo);
So now explaining you the hoisted code.
var foo = 1; // global variable;
function bar(){
var foo = function(){}; // foo is local variable of type function
foo = 10; // foo is changed to hold a number
return;
}
bar();
alert(foo); // you alert global variable.
As you can see if the code function foo(){} is present it is treated as a local variable within the bar() scope and any change to the foo is treated as a local variable change..
When you have function foo(){} in your bar() you are not even touching the global variable.. hence alerts 1.
When you don't have function foo(){} you are touching the global variable and hence alerts 10.
Now I hope you understand the output..
I know after return statement ,function foo() will not execute.
That's not true.
Function declarations are hoisted.
function foo(){} creates a local variable called foo (assigning the new function to it) and then foo = 10 overwrites it. You never test the value of that foo variable though.
In bar function , If I will remove function foo(). then alert(foo) will give me 10
You no longer have a local variable called foo so you are overwriting the global variable with the same name.
Compare:
(function() {
console.log("Version 1");
var foo = 1;
function bar() {
console.log("At top of bar, foo is " + foo);
foo = 10;
console.log("After assignment in bar, foo is " + foo);
return;
function foo() {}
}
bar();
console.log("Global foo is " + foo);
}());
(function() {
console.log("Version 2");
var foo = 1;
function bar() {
console.log("At top of bar, foo is " + foo);
foo = 10;
console.log("After assignment in bar, foo is " + foo);
return;
}
bar();
console.log("Global foo is " + foo);
}());
When you write this function :
function bar(){
foo = 10;
return;
function foo(){}
}
The javascript read this :
function bar(){
function foo(){}
foo = 10;
return;
}
The function foo is created into your local function bar. And when you write foo = 10,You overwrite the function foo in the local scope and not the global variable.
So your alert give you 1 because you never update the global variabe.
The problems here are hoisting and closure .
The declaration function foo(){} is hoisted, meaning in this case, even though it is written at the end of the function, it will be available everywhere within the scope, including before it's definition.
if function foo(){} IS NOT present, the statement foo = 10; overwrites the foo defined in the global scope. Therefore the global foo === 10.
If function foo(){} IS present, the statement foo = 10; just overwrites the function foo in the local scope, the global foo won't get touched hence global foo === 1
var foo = 1;
function bar(){
console.log(typeof foo) // function
return;
function foo() {}
}
bar();
alert(foo);
Opposed to:
var foo = 1;
function bar(){
console.log(typeof foo) // number
return;
// function foo() {}
}
bar();
alert(foo);
So basically what is happening is as if you have declared var foo = 10
because function declaration in javascript are hoisted up top
complier sees your code as follows .
var foo = 1;
function bar(){
var foo;
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
so in fact foo = 10 never overwrites the global foo;
it is kept local to the function .
so alert will get passed the global one .
In addition to my previous answer in the same thread I am
adding another answer to put in more details about the Hoisting
feature in JavaScript as the previous answer is already accepted by the OP for its content.
First lets get comfortable with what scoping is
Scoping in JavaScript
One of the sources of most confusion for JavaScript beginners is scoping. Actually, it’s not just beginners. I’ve met a lot of experienced JavaScript programmers who don’t fully understand scoping. The reason scoping is so confusing in JavaScript is because it looks like a C-family language. Consider the following C program:
#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}
The output from this program will be 1, 2, 1. This is because C, and the rest of the C family, has block-level scope. When control enters a block, such as the if statement, new variables can be declared within that scope, without affecting the outer scope. This is not the case in JavaScript. Try the following in Firebug:
var x = 1;
console.log(x); // 1
if (true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
In this case, Firebug will show 1, 2, 2. This is because JavaScript has function-level scope. This is radically different from the C family. Blocks, such as if statements, do not create a new scope. Only functions create a new scope.
To a lot of programmers who are used to languages like C, C++, C#, or Java, this is unexpected and unwelcome. Luckily, because of the flexibility of JavaScript functions, there is a workaround. If you must create temporary scopes within a function, do the following:
function foo() {
var x = 1;
if (x) {
(function () {
var x = 2;
// some other code
}());
}
// x is still 1.
}
This method is actually quite flexible, and can be used anywhere you need a temporary scope, not just within block statements. However, I strongly recommend that you take the time to really understand and appreciate JavaScript scoping. It’s quite powerful, and one of my favorite features of the language. If you understand scoping, hoisting will make a lot more sense to you.
Declarations, Names, and Hoisting
In JavaScript, a name enters a scope in one of four basic ways:
Language-defined: All scopes are, by default, given the names this and arguments.
Formal parameters: Functions can have named formal parameters, which are scoped to the body of that function.
Function declarations: These are of the form function foo() {}.
Variable declarations: These take the form var foo;.
Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter.
Function parameters and language-defined names are, obviously, already there. This means that code like this:
Ex:
function foo() {
bar();
var x = 1;
}
is actually interpreted like this:
function foo() {
var x;
bar();
x = 1;
}
It turns out that it doesn’t matter whether the line that contains the declaration would ever be executed. The following two functions are equivalent:
function foo() {
if (false) {
var x = 1;
}
return;
var y = 1;
}
function foo() {
var x, y;
if (false) {
x = 1;
}
return;
y = 1;
}
Notice that the assignment portion of the declarations were not hoisted. Only the name is hoisted. This is not the case with function declarations, where the entire function body will be hoisted as well. But remember that there are two normal ways to declare functions. Consider the following JavaScript:
function test() {
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // function expression assigned to local variable 'foo'
alert("this won't run!");
}
function bar() { // function declaration, given the name 'bar'
alert("this will run!");
}
}
test();
In this case, only the function declaration has its body hoisted to the top. The name ‘foo’ is hoisted, but the body is left behind, to be assigned during execution.
That covers the basics of hoisting. The complete 100% credit of this answer goes to ben cherry. I didnt want to post this link in my answer because the links might break and I found this completely informative and a must read for any javascript developer.
The question is, what will the following alert:
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = '11';
}
alert(typeof bar());
and the answer is, function.
My questions:
Isn't bar() being replaced by its return value? If no, why?
Isn't foo = 10; being hoisted to the top? (hoisting)
You can look at it this way:
function bar() {
var foo = function() {};
return foo; // function ends here
foo = 10;
foo = '11';
}
The other two assignment statements aren't happening.
Only declarations are hoisted in JavaScript.
For function declarations, that includes their entire statement body (which is empty in the case of foo). However, with vars, the assignments aren't considered part of the declaration and will remain where the statement was placed. (2)
To the engine, bar() appears to be:
function bar() {
// hoisted
function foo() {}
var foo; // no-op, `foo` was already declared by `function foo() {}`
// remaining statements
return foo;
// unreachable code following a `return`
foo = 10;
foo = '11'; // separated from `var foo;`
}
The resulting typeof being function is referring to the type of function foo() {}, a reference to which is what bar() returns. (1)
alert(bar().toString()); // "function foo() {}"
One of my friends was taking an online quiz and he asked me this question which I could not answer.
var global = false;
function test() {
global = true;
return false;
function global() {}
}
console.log(global); // says false (As expected)
test();
console.log(global); // says false (Unexpected: should be true)
If we assume that functions are hoisted at the top along with var variables, let's try this one.
var foo = 1;
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = 11;
}
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
Here is a JSBin Demo and JSBIN Demo2 to play with.
PS: If we remove function global() {} from test(), then it runs fine. Can somebody help me understand why is this happening ?
var statements and function declaration statements are "hoisted" to the top of their enclosing scope.
Therefore, the function global(){} in your function creates a local global name.
Assigning to global inside your functions binds to this local name. Here's how you can "rewrite" it using hoisting to understand how the compiler sees it:
function test() {
var global = function() {}; // hoisted; 'global' now local
global = true;
return false;
}
I'll answer the second part of your question,
If we assume that functions are hoisted at the top along with var variables
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
You should try console.log(bar()); console.log(foo); instead. However, what hoisting does to your function is this:
function bar() {
var foo;
function foo() {}
return foo;
foo = 10;
foo = 11;
}
So you should expect to get the function returned, since your variable assignments are after the return statement. And both the var and the function declaration make foo a local variable, so the global foo = 1 is never changed.
var foo = function () { this.bar = 1; }
>> foo.bar
undefined
How do I access the property of a function?
You syntax is wrong:
function foo() { this.bar = 1; }
var a = new foo();
a.bar; // 1
That is a definition. You need to instantiate it.
var foo = function () { this.bar = 1; }
>> new foo().bar
Another option:
var foo = function () { this.bar = 10; return this; } ();
console.log(foo.bar);
Read about self executing functions here:
What is the purpose of a self executing function in javascript?
The problem here is that you've only defined foo and not actually executed it. Hence the line this.bar = 1 hasn't even run yet and there is no way for bar to be defined.
The next problem is that when you run foo it will need a context which this will be defined in. For example
var x = {}
foo.apply(x);
x.bar === 1 // true
Or alternatively you could run foo as a constructor and access bar on the result
var x = new foo();
x.bar === 1 // true