This question already has an answer here:
Scope of Default function parameters in javascript
(1 answer)
Closed 4 years ago.
When I try to run the foo function defined in this snippet I get a ReferenceError since b is not defined.
var b = 3;
function foo( a = 42, b = a + b + 5 ) {
// ..
}
foo()
This looks like a TDZ error because b has been defined in the outer scope but it's not yet usable in the function signature as a right-hand-side value.
This is what I think the compiler should do:
var b;
function foo(..) { .. }
// hoist all functions and variables declarations to the top
// then perform assignments operations
b = 3;
foo();
//create a new execution environment for `foo`
// add `foo` on top of the callstack
// look for variable a, can't find one, hence automatically create a
`var a` in the local execution environment and assign to it the
value `42`
// look for a `var b` in the global execution context, find one, use
the value in it (`3`) as a right-hand-side value.
This shouldn't raise a ReferenceError. Looks like this is not what happens here.
Can someone explain in what actually does the compiler do and how it processes this code?
On every function call, the engine evaluates some prologue code, which contains formal parameters, declared as let vars and initialized with their actual values or default expressions, if provided:
var b = 3;
function foo( ) {
let a = <actual param for a> OR 42;
let b = <actual param for b> OR a + b + 5;
// ..
}
Since b in a function is lexical (let), it's not possible to access its value before initialization. Hence the ReferenceError.
Note that this is a call-time error, so the following compiles fine:
var b = 1
function foo(b=b) {
console.log(b)
}
The error happens when you actually call the function:
var b = 1
function foo(b=b) {
console.log(b)
}
foo()
and only when the engine actually evaluates the faulty default expression:
var b = 1
function foo(b=b) {
console.log(b)
}
foo(7)
ECMA standard reference: FunctionDeclarationInstantiation, p.21:
For each String paramName in parameterNames, do
...Perform ! envRec.CreateMutableBinding(paramName, false).
The function arguments somewhat works like 'let'.
We cannot access variable created using 'let' before they are declared .i.e variables created using 'let' are not hoisted.
This happens because if the we are declaring the variable in local scope , it cannot access the global scope variable(Unless 'this' is used )
Your code can be fixed by this -
var b = 3;
function foo( a = 42, b = a + this.b + 5 ) {
// default binding. In this case this.b = global var
}
foo()
you can also see this error if you do this.
let variable = variable;
Related
I was reading Kyle Simpson book: https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20%26%20closures/ch4.md#functions-first.
But I don't fully understand this line "Notice that var foo was the duplicate (and thus ignored) declaration, even though it came before the function foo()... declaration, because function declarations are hoisted before normal variables."
Let's say this is the code:
console.log(foo); // The output is: foo() { return 2; }
function foo() {
return 1;
}
function foo() {
return 2;
}
var foo = 3;
I want to visualize what would be the output in JS Engine after Memory Creation phase. Will it be like this?
function foo() {
return 2;
}
console.log(foo);
If yes, why var foo = 3; was ignored? There is no duplicate for var in the snippet. If no, can anyone please help me visualize what would be the output in JS Engine after Memory creation phase?
Thanks
I think the text refers to
// scope creation
var foo; // the name was declared. Thrice.
foo = undefined; // from the var
foo = function foo() { return 1 }; // from the first declaration
foo = function foo() { return 1 }; // from the second iteration
// execution
console.log(foo);
;
;
foo = 3;
where foo is initialised with undefined due to the var foo declaration, but then gets overwritten by the initialisation value from the function foo declaration which takes precedence - regardless of the order in which the declarations appeared in the code, function declarations overrule var declarations.
Function declarations
Declare a variable with the same name as the function (this is hoisted)
Assign the function to that variable (this is hoisted)
var statements with associated assignments
Declare a variable with that name (this is hoisted)
Assign the value to that variable (this is not hoisted)
var foo = 3 is not ignored.
The variable declaration (var foo) is ignored because the earlier function declarations already declared that variable. (i.e. because it duplicates the declaration of foo).
foo = 3 is not ignored and does assign 3 to foo … it just does so after your console.log statement runs because it isn't hosited.
I am trying to understand what is going "under the hood". Other questions dont explain the mechanics I am interested it. Please see code under.
I am looking for steps like this:
(p.foo = o.foo)(); expresion
Value of o.foo is hold somewhere and is not yet related to p obj?
Value of o.fooget executed?
p.foo gets the value on o.foo?
is this right? if yes then need more info in step 2 on how, where and why...
function foo() {
console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // we get 2 and not 4”
There is nothing special happening here.
This line
(p.foo = o.foo)();
is equivalent to executing below function in global scope(this refers to window) where value of a is 2 which gets printed.
function foo() {
console.log( this.a );
}
following assignment returns function definition
p.foo = o.foo
its not executing foo on p or o object. its just adding property foo on p object and assigning it that function.
Hence , you end up executing code in global scope
(function () {
console.log( this.a );
})()
p.foo = o.foo is an expression. All expressions resolve to a value. In this case, it's the function foo().
So basically, when you call this code, you not only assign a new value to p.foo (because it so happens that the expression contains the assignment operator =) -- you also get back the global function foo as a result of evaluating the expression.
You then call the function inline in the window context, where a equals to 2.
In the following code, why can I access the variable x.b? Shouldn't it have a local scope?
CODE
function x() {
var a = 3;
}
x.b = 8;
console.log(x.a);
console.log(x.b);
OUTPUT
undefined
8
When you use var to declare a within x's constructor, a is mark as private, however when you do x.b you are essentially saying - add the property b to the object x.
Hence when you do x.b, technically speaking you are accessing object x's property b, which is 8.
Javascript considers x.b as a global object. so you can access it even inside the function like:
x.b = 8;
function x() {
var a = 3;
alert(x.b)
}
x();
console.log(x.a);
console.log(x.b);
But make sure you specify x.b before function declaration.
whereas object a is specified inside the function x() which makes it private thats why you are getting undefined result for console.log(x.a);
if you write it like this:
a = 5;
function x() {
var a = 3;
}
x.b = 8;
alert(a);
alert(x.b);
you will get results as bellow:
5
8
for javascript a and x.a are two separate objects.
You have defined x.b to 8 and it becomes a global var. Which means you can access it from anywhere.
So the x() is a function which has its own scope. So you can't access the vars inside a function scope in the mentioned way. However you can access the 'a' by doing this and calling the x function.
function x() {
var a = 3;
return a;
}
I understand functions in 'js' have lexical scope (i.e. functions create their environment (scope) when they are defined not when they are executed.)
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined
When I run just 'f()' it returns the inner function. Which I get, that's what 'return' does!
function f() {
var b = "barb";
return function() {
return b;
}
}
console.log(b); //ReferenceError: b is not defined
Why do you get 'ReferenceError: b is not defined?'
But doesn't the inner function above have access to it's space, f()'s space etc. Being that 'b' is being returned to the global space, wouldn't the console.log() work?
However when I assign 'f()' to a new variable and run it:
var x = f();
x();// "barb"
console.log(b); //ReferenceError: b is not defined
This returns 'b' which is "barb", but when you run console.log() again you'll get 'ReferenceError: 'b' is not defined'; Isn't 'b' in the global scope now since it has been returned? SO why didn't 'x()' also return the inner function just like 'f()' did?
You, my friend, are thoroughly confused. Your very first statement itself is wrong:
functions create their environment (scope) when they are defined not when they are executed
Actually it's the opposite. Defining a function doesn't create a scope. Calling a function creates a scope.
What's a scope?
To put it simply, a scope is the lifespan of a variable. You see, every variable is born, lives and dies. The beginning of a scope marks the time the variable is born and the end of the scope marks the time it dies.
In the beginning there's only one scope (called the program scope or the global scope). Variables created in this scope only die when the program ends. They are called global variables.
For example, consider this program:
const x = 10; // global variable x
{ // beginning of a scope
const x = 20; // local variable x
console.log(x); // 20
} // end of the scope
console.log(x); // 10
Here we created a global variable called x. Then we created a block scope. Inside this block scope we created a local variable x. Since local variables shadow global variables when we log x we get 20. Back in the global scope when we log x we get 10 (the local x is now dead).
Block Scopes and Function Scopes
Now there are two main types of scopes in programming - block scopes and function scopes.
The scope in the previous example was a block scope. It's just a block of code. Hence the name. Block scopes are immediately executed.
Function scopes on the other hand are templates of block scopes. As the name suggests a function scope belongs to a function. However, more precisely, it belongs to a function call. Function scopes do not exist until a function is called. For instance:
const x = 10;
function inc(x) {
console.log(x + 1);
}
inc(3); // 4
console.log(x); // 10
inc(7); // 8
As you can see every time you call a function a new scope is created. That's the reason you get the outputs 4, 10 and 8.
Originally, JavaScript only had function scopes. It didn't have block scopes. Hence if you wanted to create a block scope then you had to create a function and immediately execute it:
const x = 10; // global variable x
(function () { // beginning of a scope
const x = 20; // local variable x
console.log(x); // 20
}()); // end of the scope
console.log(x); // 10
This pattern is called an immediately invoked function expression (IIFE). Of course, nowadays we can create block scoped variables using const and let.
Lexical Scopes and Dynamic Scopes
Function scopes can again be of two types - lexical and dynamic. You see, in a function there are two types of variables:
Free variables
Bound variables
Variables declared inside a scope are bound to that scope. Variables not declared inside a scope are free. These free variables belong to some other scope, but which one?
Lexical Scope
In lexical scoping free variables must belong to a parent scope. For example:
function add(x) { // template of a new scope, x is bound in this scope
return function (y) { // template of a new scope, x is free, y is bound
return x + y; // x resolves to the parent scope
};
}
const add10 = add(10); // create a new scope for x and return a function
console.log(add10(20)); // create a new scope for y and return x + y
JavaScript, like most programming languages, has lexical scoping.
Dynamic Scope
In contrast to lexical scoping, in dynamic scoping free variables must belong to the calling scope (the scope of the calling function). For example (this is also not JS - it doesn't have dynamic scopes):
function add(y) { // template of a new scope, y is bound, x is free
return x + y; // x resolves to the calling scope
}
function add10(y) { // template of a new scope, bind y
var x = 10; // bind x
return add(y); // add x and y
}
print(add10(20)); // calling add10 creates a new scope (the calling scope)
// the x in add resolves to 10 because the x in add10 is 10
That's it. Simple right?
The Problem
The problem with your first program is that JavaScript doesn't have dynamic scoping. It only has lexical scoping. See the mistake?
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined (obviously - f2 can't access the `a` inside f1)
Your second program is a very big mess:
function f() {
var b = "barb";
return function() {
return b;
}
}
console.log(b); //ReferenceError: b is not defined
Here are the mistakes:
You never called f. Hence the variable b is never created.
Even if you called f the variable b would be local to f.
This is what you need to do:
function f() {
const b = "barb";
return function() {
return b;
}
}
const x = f();
console.log(x());
When you call x it returns b. However that doesn't make b global. To make b global you need to do this:
function f() {
const b = "barb";
return function() {
return b;
}
}
const x = f();
const b = x();
console.log(b);
Hope this helped you understand about scopes and functions.
You get, "ReferenceError: b is not defined" because "b" is not defined where your console.log() call is. There's a "b" inside that function, but not outside. Your assertion that "b is being returned to the global space" is false.
When you invoke the function returned by your "f()" function, that will return a copy of the value referenced by that closure variable "b". In this case, "b" will always be that string, so the function returns that string. It does not result in the symbol "b" becoming a global variable.
But doesn't the inner function above have access to it's space, f()'s space etc.
Yes it has. It accesses the b variable and returns its value from the function.
Being that 'b' is being returned to the global space
No. Returning a value from a function is not "making a variable available in the caller scope". Calling the function (with f()) is an expression whose result is the value that the function returned (in your case, the unnamed function object). That value can then be assigned somewhere (to x), a property of it can be accessed or it can be discarded.
The variable b however stays private in the scope where it was declared. It is not [getting] defined in the scope where you call console.log, that's why you get an error.
What you want seems to be
var x = f();
var b = x(); // declare new variable b here, assign the returned value
console.log( b ); // logs "barb"
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined
f2(); does not knows about the a,because you never passed 'a' to it,(That's Scope are
created when the functions are defined).Look function f2() would have been able to acess
a if it was defined inside f1();[Functions can access the variables in same scope in
which they are "DEFINED" and NOT "CALLED"]
function f() {
var b = "barb";
return function(){
return b;
}
}
console.log(b);
First of all You Need to Call f(); after executing f(); it would return another function
which needs to be executed. i.e
var a=f();
a();
it would result into "barb" ,In this case you are returning a function not the var b;
function f() {
var b = "barb";
return b;
};
console.log(f());
This would print barb on screen
This question already has answers here:
Javascript function scoping and hoisting
(18 answers)
Closed 8 years ago.
I was reading this article and I have some questions please:
considering this code :
1: var a = 1;
2: function b () {
3: a = 10;
4: return;
5: function a() {}
6: }
7: b();
8: alert(a);
this will alert 1. ( my question is why ? )
the article states its related to Name resolution.
Name resolutions (according to the article ) is being determined by this order:
1. Internal mechanisms of language: for example, in all scopes are available “this” and “arguments”.
2. Formal parameters: the functions can be named as the formal parameters, which scope is limited to the function body.
3. Function declarations: declared in the form of function foo() {}.
4. Variable declarations: for example, var foo;.
line #3 suppose to change the value of the global a.
but the function a(){...} have a priorty over the inside a declaration ( If i understood correctly)
and thats why is alerts 1
p.s. if i remove line #5 , it will alert 10.
In general, if a name is already defined, it will never be redefined
by another entity with the same name. That is the function declaration
has a priority over the declarations of the variable with the same
name. But this does not mean that the value of a variable assignment
does not replace the function, just its definition will be ignored.
I dont understand that part :
But this does not mean that the value of a variable assignment does
not replace the function
so 2 questions please :
Did I understand correctly the reason for alerting 1
What does the above line means ? (the misunderstood part)
thanks.
Did I understand correctly the reason for alerting 1
Yes
"But this does not mean that the value of a variable assignment does not replace the function"
What does the above line means ? (the misunderstood part)
It just means that although a function with name a is already defined, a = 10 is still going to be executed, i.e. after that line a does not refer to a function anymore but to 10.
I assume they wanted to relax the previous statement a bit and avoid that people incorrectly think that because the function declaration is executed first, the assignment would not take place anymore.
Function and variable declarations are hoisted to the top of the scope. So the code is equivalent to:
1: var a = 1;
2: function b () {
3: function a() {}
4: a = 10;
5: return;
6: }
7: b();
8: alert(a);
function a() {...} creates a symbol (variable) a in the local scope and its value is the very same function. The next line, a = 10;, then assigns a new value to that symbol, namely a number.
var a = 1;
function b () {
function a() {} // creates a new local symbol `a`, shadowing the outer `a`
// until here, `a` refers to the function created
// created by the above declaration
a = 10; // now a new value is assigned to the local symbol/variable `a`
// from here on, `a` is `10`, not a function
return;
}
b();
alert(a);
var a = 1;
function b () {
var a = 10;
}
b();
alert(a);
does the above example make sense to you? Yes? Good, then you understand the difference between local and global scope...
var a = 1;
function b () {
a = 10;
var a;
}
b();
alert(a);
Does this example make sense to you? Yes? Then you understand that it does not matter where a variable is declared in a function, it will always be declared when first entering the function.
var a = 1;
function b () {
a = 10;
var a = function() { };
}
b();
alert(a);
Now, does this example make sense? Yes? Then you understand dynamic typing. A variable can be assigned a function as a value and then can be overwritten with a integer such as 10.
var a = 1;
function b () {
a = 10;
return;
function a() { }
}
b();
alert(a);
Now your example should make sense because we are just changing the way we declare a, but its the same thing.
From my understanding of hoisting, both variable declarations and function declarations are hoisted. Therefor, here's what's happening:
var a; // a is declared (hoisted)
function b () { // function declaration (hoisted)
function a () {} // function declaration (hoisted)
a = 10; // an assignment to the local a that was hoisted, not the outer a
return;
}
a = 1; // initialization (not hoisted)
b(); // hoist inside b's scope causes an inner a to be modified
alert(a); // alerts 1 since the outer a was never modified