I'd like to understand the debugging content during the execution of the following code:
var z = 2;
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
var x = 3;
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
var squareoftwoplusother = (SQUAREPLUSOTHER)(x);
x = 4;
z = 4;
var result = squareoftwoplusother(5);
console.log("result", result);
Now....
At the call of:
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
the debug shows clearly:
squareoftwoplusother: undefined
SQUAREPLUSOTHER: x=>...
x: 3
z: 2
at the following call of:
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
the debug shows:
Local:
x: 3
Closure
z: 2
at the following call of:
x = 4;
z = 4;
the debug shows:
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
x: 4
z: 4
at the following call of:
var result = squareoftwoplusother(5);
the debug shows:
result: 18
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
Local:
x: 5
Closure
x: 3
Closure
z: 4
and at the final calls the debug shows:
result: 18
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
x: 4
z: 4
now the questions:
How many "Closures"? They belongs to? (i.e. how to explain...)
Local:
x: 5
Closure
x: 3
Closure
z: 4
How the scope of the variables is managed in javascript?
How to have a "definitive" idea in terms of "context" or "whatever it be" about the mess of closure :-)?
thanks in advance
Ed
Every time a function is called, a local scope is created for that function. If there is still a reference to that local scope after the function returns, then a closure is created. Once the reference is gone, the closure is also garbage collected.
If you add breakpoints to the first line of every function, you will see that scopes are created that may later become closures.
A great explanation is given here http://dmitrysoshnikov.com/ecmascript/javascript-the-core/#activation-object
I'll add some braces to your code to make that easier and I'll add self calling function to add a level of closures.
(() => {
var z = 2;
var SQUAREPLUSOTHER = (x) => {
debugger;
return (y) => {
debugger;
return (x * x) + y + z;
}
};
var x = 3;
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
var squareoftwoplusother = (SQUAREPLUSOTHER)(x);
x = 4;
z = 4;
var result = squareoftwoplusother(5);
console.log("result", result);
debugger
})()
The screenshots below are from Chrome DevTools which minimizes the closures, that is, it only maintains references to what is needed. Back in the days, the entire closure was always available and you could prove it because it showed up in the closures pane of debuggers. See Javascript closures performance for further details
Scope
There are just three different scopes in your code. One is the global scope all variables you declare in and the other two are here:
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
There are two function scopes, one containing the variable x and the other function scope containing the variable y. It might be easier to see if you replace the arrow function with functions:
// global scope
function SQUAREPLUSOTHER(x) {
// function scope containing x
return function(y) {
// function scope containing y
return (x*x) + y + z;
};
}
How scoping works is actually quite simple:
Every { starts a new scope and its counter } closes it, variables declared inside it with let and const (or var but thats slightly more complicated) are part of the scope. If it is the scope of a function, the parameters (e.g. x and y) are part of that scope.
From the code, you can access the all variables that are in the current scope or in its parent scope, if there are multiple with the same name you get the most inner one. Therefore x inside of the SQUAREPLUSOTHER function refers to the variable of the SQUAREPLUSOTHER scope, while for code outside of it x is the global variable and the functions variable can't be accessed.
The Scope of a variable does not change at runtime, you can always directly see which scope a variable belongs tp by looking at the surrounding { .. }.
Now different variables in different scopes have to hold values at runtime, thats where we get to:
the environment record
When you call a function, the JavaScript engine creates a new "EnvironmentRecord" (which is like an internal object) that contains all the variables of the function you call, e.g. in this case:
function test(a) {
let b;
}
Then if you call that function (test(1)) a new environment record gets created that contains a and b. Now the code inside the function gets run, and every variable is looked up in it. If there are two functions nested into another, calling the inner function will create an environment record that holds a reference to the outer one:
function test(a) {
function test2(b) {
}
test2(5);
}
Now calling test(1) will create an record where a is 1. If the engine then executes the second call (test2(5)) it creates another record containing b being 5, and that holds a reference to the record containing a. Now if you use a inside test2, the engine will look it up in the current environment record, won't find it, and then look it up in the parent where it finds a being 1.
closure
Usually those records get deleted when the execution reaches the }, however if there is another record that got the current record as a parent, it won't get deleted. It will exist until all child records got deleted, then it will also remove the parent. This behaviour (variables live longer because they can be accessed from an inner functions body) is called a closure.
Related
var x = 3;
var one = {
x:2,
two: {
x:1,
three:function(){
return this.x;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "" + go());
Anyone can explain to me why output coming 13 why not 1-undefined?
this keyword has a different binding that can change during runtime, depending on how the function was invoked.
When a function is on an object, and is accessed through that object, it's this context will be that object (unless explicitly bound otherwise, but I'll add notes on that later). This means this.x is referencing the same variable as one.two.x
When you reference that same function into a global variable, the this context becomes the global space (e.g. the window object on browsers, or globalThis in NodeJS). When this happens, this.x is now referencing global variable x.
There are other situations where this context rules are different, such as function closures or class functions.
Functions also have .bind method that returns a new function with an explicitly bound this variable.
e.g:
var x = 3;
var one = {
x:2,
two: {
x:1,
three:function(){
return this.x;
}
}
}
one.two.three = one.two.three.bind(one);
var go = one.two.three;
console.log(one.two.three() + "" + go()); // prints 22
There are also arrow functions, which implicitly have the this context bound to it's lexical scope... e.g:
var x = 3;
var one = {
x:2,
two: {
x:1,
three: () => {
return this.x;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "" + go()); // prints 33
This above example prints 33, because the lexical scope is the global scope, thus this.x is referencing global variable x.
Hope this answers your question without creating more questions.
Further Reading:
this keyword
Interesting. I think it has something to do with scopes.
console.log(one.two.three() + "" + go());
//equals console.log(1 + "" + 3);
will output 13 (String) because:
one.two.three() returns 1
go() returns 3
those numbers are concatenated into String with "" (empty string) in between (instead of - as you may have asked)
Why go() returns 3
var x = 3;
// var go = one.two.three;
// equals
var go = function() {
return this.x
}
The declaration var go = one.two.three; assigns one.two's three method as a function into the variable go in the global scope. The same scope with go, one, and x (with the value 3), that was declared before declaring one and go (var x= 3;).
Based on your whole codes, this.x's this is in the global scope. and this.x is 3. So running go() returns 3.
one.two.three is a global function
→ notice there's no (), so assigning a function to global scope's variable go will make the function's scope global.
→ go function is run under global's scope
Why one.two.three() returns 1
Well, one.two.three is a method inside the object two, which is inside the object one. While the definition looks the same,
function() {
return this.x;
}
when you run three method of two object, return this.x's this refers to the method's parent object (which is two, three's parent object is two).
So,
this.x refers to
two.x which is 1.
Hence, in this case return this.x; outputs 1.
one.two.three() is 1
→ notice the () which means run the function
→ three method is run under two's scope
Addition
This will output 1-undefined because:
y is not defined in the global/one/go scope
I use - as a delimiter in console.log
var one = {
y:2,
two: {
y: 1,
three:function(){
return this.y;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "-" + go());
To assign an object method to a variable, it needs to be bandaged using the bind() function, and if the global variable window is passed to the context, the answer will be 13
*var go = one.two.three.bind(window);*
if the object is one the answer will be 12
*var go = one.two.three.bind(one);*
if the object is two the answer will be 11
*var go = one.two.three.bind(two);*
function foo(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o1 = {};
foo(o1); // 2 (x is visible even outside the with statement because of *var*)
function foo2(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o2 = {
x: 1
};
foo2(o2); // undefined (why?)
I'm reading along Kyle Simpson's Scope & Closures book from the YDKJS series and I was able to understand all of the quirks of with statements and how with(obj) { a = 1 } is functionally different from obj.a = 1 despite having been intended as a shorthand for it in cases of long object names and having to constantly reference it. This is because the object's properties are treated as lexically defined identifiers in that scope (a vs obj.a), and that in sloppy mode, one side effect of this is that if the object you pass into a with statement doesn't have a property that you are trying to assign to, a global variable of that name will be created. Still, armed with all this knowledge and more, I don't quite understand why the code above behaves the way it does. Why does foo(o2) log undefined?
The difference in behaviour can be accounted for by this behaviour, described in (for instance) the following note in ECMAScript 2022 Language Specification sect 14.3.2.1:
NOTE: If a VariableDeclaration is nested within a with statement and the BindingIdentifier in the VariableDeclaration is the same as a property name of the binding object of the with statement's object Environment Record, then step 5 will assign value to the property instead of assigning to the VariableEnvironment binding of the Identifier.
In the first case:
function foo(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o1 = {};
foo(o1);
because obj has no x property, the var statement is hoisted to the top of the function and is therefore visible beyond the scope of the with statement.
In the second case:
function foo2(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o2 = {
x: 1
};
foo2(o2);
x exists on obj, so we satisfy the conditions laid out in the quoted note, and therefore the value is assigned to the property and no hoisted variable is created. Now, there's no x outside the scope of the with statement.
The W3Schools example for a JS for-each loop (http://www.w3schools.com/js/js_loop_for.asp) is
var person = {fname:"John", lname:"Doe", age:25};
var text = "";
var x;
for (x in person) {
text += person[x];
}
and I'm wondering if there's any particular reason why x is defined outside of the loop if it's only used inside the loop in that particular example, or if that's necessary condition for defining a for-each loop, and if so, why?
This is(/was) an old convention, meant largely to indicate that x does not exist only inside the loop.
Declaring variables at the top of a function is not necessary and is variously encouraged/discouraged by different style tools. It can be convenient to group variable declarations in one place, but may increase the distance between declaration and use (generally considered a bad thing).
In JS, the var declaration works at function-scope, so variables are hoisted to the top of the nearest function and live for the duration of the function. See:
function foo() {
for (var i = 19; i > 0; --i) {
console.log(typeof i); // number
}
console.log(typeof i); // number
}
foo();
Because the variable is accessible throughout the function, it is declared at the start of the function (C used to require this).
ES6 has changed this with the let statement, which introduces the more common block-level scoping. With let, the variable is only available inside of the loop:
function foo() {
for (let i = 19; i > 0; --i) {
console.log(typeof i); // number
}
console.log(typeof i); // undefined
}
I'm trying to expand my modest level of JavaScript skills by learning how to use closures. In the code below, I thought I'd see console.log output counting down from 3 to 0. Instead, I'm getting -1, -1, -1, -1.
I know I'm dealing with scoping issues, but that's about it. What's missing? How should this be properly written, and why?
function closure_count_test (number)
{
for (var x = 0; x <= number; x += 1)
{
setTimeout(function() {console.log(number - x);}, x * 1000);
}
}
closure_count_test(3);
Your logic is correct. The problem is that setTimout only considers the latest value of the variables. So the setTimout always get x = 0 since it is the last in the loop.
you can see your desired output if you remove the setTimout function.
x is iterated by the for loop, but the function in setTimeout uses the variable x, which is not interpolated at the time the function is created. This causes it to use whatever the final value of x is (because the setTimeouts execute after the loop completes).
In order to get around this, you have to pass the value of x as it is to the callback of setTimeout. You can call a function that returns another function (the new callback):
for (var x = 0; x <= number; x += 1) {
setTimeout(
(function (x) {
return function () { console.log(number - x) };
})(x)
, x * 1000);
}
This passes x from the outer scope with its current value to the inner scope. The inner function uses whatever value x was when the function was created.
A function is returned to work properly with setTimeout.
http://jsfiddle.net/ExplosionPIlls/QhA3a/
How scoping works in basic words is, it makes variables of a main function, that are referenced in nested functions stay after function ends, and all of these functions can later access them.
In provided example x is a variable defined in the main function, and all nested functions will later be able to reference it. By that time the value of x will be number+1, so your result makes perfect sense. To workaround that, you must avoid referencing the variable of the main function. Here's the normal technique:
function closure_count_test (number)
{
for (var x = 0; x <= number; x += 1)
{
setTimeout(function(x) {
return function() {console.log(number - x);}
} (x), x * 1000);
}
}
What you do here, is you call several nested functions, which have their own x copied as an argument, and each of these have one nested function that will reference that argument via scope.
this works because x being to be localised inside one more closure
function closure_count_test(number) {
for (var x = 0; x <= number; x++) ( // not need {} as here is only one operator
function (x) { //Now x - local variable in anonymous function
return setTimeout(function () {
console.log(number - x);
}, x * 1000);
}(x) // pass x to anonymous function as argument
);
}
closure_count_test(3);
In the following code, can the x member be accessed from the nested object literal?
var outer = {
x : 0,
inner: {
a : x + 1, // 'x' is undefined.
b : outer.x + 1, // 'outer' is undefined.
c : this.x + 1 // This doesn't produce an error,
} // but outer.inner.c is NaN.
}
In the way you put it - no.
You need two stages construction, this will work:
var outer = { x : 0 };
// outer is constructed at this point.
outer.inner = {
b : outer.x + 1 // 'outer' is defined here.
};
Not in the construct you have there, no.
The main reason being that outer doesn't actually exist yet when you are inside inner.
If you changed the properties of inner to functions you could access outer at runtime, but it would be pretty ugly code.
Consider using new outer(); instead and build an object that way, then you can use this inside inner, but then that is a completely different construct and would look something like
var outer = function() {
this.x = 0;
this.inner = {
a: this.x + 1
};
};
var b = new outer();
console.log(b.inner.a); // 1
I don't think that sort of construct would make sense. I don't think there's anything stopping you from saying
var outer2;
outer2.inner = outer.inner;
In that scenario, how would you distinguish between the two parents?
The way to do it is probably with more of a constructor type function, with a parameter that gets assigned to outer.x and inner.whatever as needed.
You could also use a closure:
var outer = function outer() {
var x = 0;
return {
inner : {
a: x + 1
}
}
};
var b = outer();
console.log('a is ' + b.inner.a);
//a is 1
For a great article on closures check out the javascript garden
http://bonsaiden.github.com/JavaScript-Garden/#closures