JavaScript Closures - function scope [duplicate] - javascript

This question already has answers here:
How are closures and scopes represented at run time in JavaScript
(2 answers)
About closure, LexicalEnvironment and GC
(3 answers)
Closed 5 years ago.
I have a question related to JavaScript Closures, in specific to the scope when calling a (inner) function.
The question also relates to browser memory leaking as we will see.
At first a "short" introduction to my problem:
So I know when a function is called it enters an execution context (which is added on top of the call stack). There an "Activation object" is created with all the local variables, the function's arguments object and parameters added to it (as properties).
Since inner functions can access variables of enclosing functions - even if the inner function is called after the execution of its enclosing function has ended - there has to be some reference to the "free" (= outer) variables. This is managed by the scope chain which is also added to the execution context.
According to this site, the execution context's scope consists of the actual Activation object at the top of a list which is hiddenly saved on the function itself:
A scope consists of a list (or chain) of objects. Each function object has an internal [[scope]] property [...] The scope that is assigned to the execution context of a function call consists of the list referred to by the [[scope]] property of the corresponding function object with the Activation object added at the front of the chain (or the top of the list).
This is completely logic because due to this internal scope property, references to the free variables exist and so firstly the Closure is able to reach the variables (by going through the scope chain) and secondly it prevents the Garbage Collector from freeing the associated memory when the execution of the enclosing function ends.
In short: the scope chain (including the function's internal scope property) is the reason why Closures work as they do.
So now concretely to my question:
Which variables are added to the function's internal scope property?
As i understand the following part of this MDN article:
A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time that the closure was created.
... this would mean that references to all local variables would be added to the internal scope property when forming a Closure.
This seems a bit unnecessary, when the Closure doesn't use all the local variables from its enclosing function, but no matter; the real problem is that this would lead to memory leaks as we will see in the following.
Consider following code (it's a small reduction of this article, to which we will come to later):
var theThing = null;
var replaceThing = function () {
var priorThing = theThing; // hold on to the prior thing
theThing = {
longStr: new Array(1000000).join('*'), // create a 1MB object
someMethod: function () {
console.log("someMessage");
}
};
};
setInterval(replaceThing, 1000); // invoke `replaceThing' once every second
After the first function call of replaceThing following would happen:
priorThing = null
theThing references to a new object (let's say with address 0x01) containing following properties:
a 1MB object
function someMethod whose internal scope property has references to all local variables of the enclosing function, this means also to priorThing which is null
After the second function call:
priorThing = reference to object with address 0x01
theThing references to a new object (let's say with address 0x02) containing following properties:
a 1MB object
function someMethod whose internal scope property has a reference to priorThing (with the address 0x01)
priorThing itself points to a object with the same structure ...
So what's happening?
On each function call a new object is created which references to the object created in the function call before; although we don't even use this object in our new object. It just happens due to the scope chain of the function closure.
So we see saving references to all local variables of the enclosing function is pretty bad.
A better way would be to just save these we really need.
So, from the previous article I conclude that this is really done so and this would solve the memory leak problem I described above.
But furthermore it says following:
But as soon as a variable is used by any closure, it ends up in the lexical environment shared by all closures in that scope.
Well, this would create another possibility to create memory leaks as the author describes in his example - but this would be a programmer's bug.
Okey, so now summed up shortly:
Are all local variables referenced in the closure's scope? (as MDN says)
Would be the worst, because of memory leaks.
Are the variables referenced by all closures if any closure uses it? (as this source says)
Would be the best, because memory leaks are avoided - but bugs could happen, if the programmer isn't aware of this behaviour.
Or does every closure have its own references depending on which variables are used by themselves?
Would completely avoid memory leaks, but a bit more memory would be needed because there has to be a own "lexical environment" object (which is referenced by the internal scope property) for each closure.

Related

Are JavaScript execution contexts and JavaScript objects the same thing from a logical point of view?

My understanding of JavaScript is that on script execution a global execution context is created - what I understand to be a series of key:value pairs in reserved memory space - much like a regular JavaScript object.
On function execution, a new execution context is created with access to the 'parent' execution context. This seems (to me) at least to be the equivalent of re-initializing the JavaScript execution environment. Except that non of the key:value pairs initially set up in the global object need to be added to the new execution context since the child execution context has access to the parent's key:values pairs.
So for example:
function Y() {
this.prop = 4;
};
Y.prototype.doY = function() {
console.log(this.prop);
};
function X(){
this.prop = 5;
this.y = Object.create(Y.prototype);
Y.call(this.y);
};
// I can instantiate the object like so:
var x = new X();
// Which is equivalent to the following:
var x = Object.create(X.prototype);
X.call(x);
// Then I can add a function to the object that the X constructor points to via the X.prototype reference:
X.prototype.doX = function() {
console.log(this.prop)
};
// And then i can execute doX() in the context of the x object
x.doX(); // 5
x.y.doY(); // 4
On execution, doX function creates an execution context referenced from within the x object. The x object in turn is referenced within the global object.
Likewise, on execution the doY function creates an execution context that is referenced from within the x.y object.
It seems to me that an execution context as created by function execution is basically equivalent to a JavaScript object from a logical point of view:
Both allow for variable declaration NOT visible to parent objects/execution contexts
Both contain some kind of internal reference to parent object/execution context
It seems that both objects and execution context are just a list of key:values, the whole list being referenced by a single (ONLY a single) parent object (i.e. the y object exists as a reference within the x execution context) - or the global object as the root parent object (the x object exists as a reference within the global execution context).
So the question is: Is JavaScript execution context the same as a JavaScript object? If not, what is the difference?
This question: Are Execution Context and Variable Object actually same thing in JavaScript? mentions that in terms of implementation, that an execution context and an object are NOT the same thing.
Would it be correct to say that execution context inherits from Object? Or is implementation of objects/execution contexts completely non-related... One difference that I can see is that on creation, an execution context is 'processed' from top to bottom (lexically speaking) allowing an author to specify imperative commands - i.e. instruct the computer to do things. But in terms of architecture, this difference seems like an extension of the idea of an object rather than something completely different.
It seems to me that a 'running JavaScript environment' if such a thing exists, is basically a tree. The root node is the global execution context, and creating object adds nodes to the root node, or (as in the case of y above), adds nodes to the child nodes. Child nodes then reference parent nodes via a property to allow for scoping to parent execution context.
Then in terms of closures, which involve creation (and execution) of an execution context, on return the resultant object seems EXACTLY like a regular object since the 'execution context' as referenced by the closure will never again be executed (i.e. the same function, re-executed would create a new execution context and closure).
So from an "applied" point of view, is there ever a time that this -> i.e. a self reference to the current execution context, is NOT the same as the object from which a function call is made (aside from when using call, apply, or bind)? i.e. in the case of x.y.doY(), the function doY is called from the x.y object.
Execution contexts are conceptually objects, yes, as are several other things in the specification. That doesn't make them the "same" as JavaScript objects. They're a specification device and may not literally exist at runtime at all; code cannot directly reference them. For the full picture, read Executable Code and Execution Contexts in the spec.
Is JavaScript execution context the same as a JavaScript object?
No. A JavaScript object can be directly referenced by code, has a prototype, and has specific behaviors described for it which are not described for execution contexts, etc.
Would it be correct to say that execution context inherits from Object?
No, nothing in the spec suggests that to be the case.
It seems to me that a 'running JavaScript environment' if such a thing exists, is basically a tree.
Sort of, fairly indirectly. The spec doesn't describe any link from an execution context to its parent or child contexts. Instead, the lexical environment objects which are part of the context's state (specifically the LexicalEnvironment and VariableEnvironment state components) have a link to their parent lexical environment for the purposes of binding resolution. (The parent lexenv doesn't have a link to its children in the spec.) But they, too, are purely a specification device which may not literally exist at runtime and cannot be directly referenced by code.
So it's absolutely correct to think of them as objects, that's how the spec describes them, but they aren't JavaScript objects in the way that term is normally understood — something code can directly reference and act upon.
No, they are not the same thing. Not at all.
First, you seem to be confusing execution contexts with environment records. The former are basically call stack frames, the latter ones store variable values and form a tree as you described. Let's talk about environment records.
Environment records feature a key-value mapping and a link to their parent environment. In that regard, they are similar to a JS object with its properties and prototype link indeed. In fact, in a with statement or the global scope a so called object environment record is backed by an actual JS object.
However, they are still very different. Most environment records are declarative, that means their shape is determined before they are used. They are like an object that is not extensible. Also they cannot have getter/setter properties. And they differ in many more minor details.
But most importantly, environment records are just specification type values. They "are specification artefacts that do not necessarily correspond to any specific entity within an ECMAScript implementation. Specification type values may be used to describe intermediate results of ECMAScript expression evaluation but such values cannot be stored as properties of objects or values of ECMAScript language variables." So no, they do not inherit from Object at all.
Your question seems to ask: what can execution contexts record do that cannot be recorded in javascript objects?
You've got well documented answers already. So my contribution will be practical examples.
How would you manage the following 2 examples from a key/value perspective:
// Execution context of anonymous functions
(function (x) {
var y = x+1;
console.log(y);
}) (1);
// Life cycle of objects versus reference
var x = {a:1};
var y = x;
x = {b:1};
console.log(y);
If you start inventing keys that are not in the code, you should realize that this approach is limited. And so, not working if you push beyond the limits.

What does the window object contain?

I was exploring the this keyword in the global scope, and discovered that this in that context refers to the window.
I logged the value of this to the console, and saw a huge list shown in the image below.
What does the list I'm seeing contain, and how is it populated?
First, a brief definition for readers of what a lexical environment is, as well as how it relates to the global environment, and in turn how the global environment relates to the global object.
A lexical environment consists of:
an environment record, which stores the identifier bindings created within the scope of the environment,
a reference to an outer environment, and
references to any environments contained within.
Lexical environments inherit variable definitions declared in the environments they are contained within, and are created each time a function declaration, a block statement, or a catch clause of a try statement is evaluated. Variable definitions are not accessible outside the lexical environment they were defined in.
The following example:
defines a global variable using a var declaration, initialized to a function expression, which creates a new lexical environment,
defines a variable in the new environment, again using a var declaration, this time initialized to a string value, and
demonstrates that the variable is not accessible outside of the environment it is defined in:
var hello = function() {
var world = "fubar";
console.log(world); // "fubar";
}
console.log(world); // ReferenceError: world is not defined
The global environment is a lexical environment whose outer environment reference is null, and which includes an associated global object whose properties provide some of the global environment's identifier bindings, specifically excluding variables defined using let or const declarations, as well as other possible exclusions.
var hello = "world";
console.log(hello, window.hello); // "world", "world"
let foo = "bar";
console.log(foo, window.foo) // "bar", undefined
Now, to answer your question in context:
What does the list I'm seeing contain, and how is it populated?
The list you are seeing contains the properties of the global object, which consists of:
prepopulated identifier bindings supplied by the browser - some of which are standard, others are specific to the JavaScript engine or browser implementation -
global variables set by scripts running on the current page, or
global variables set by browser extensions you may have installed.
The information contained in this answer should conform to the ECMAScript 2015 Language Specification, which also contains definitions for most of the terms used here, and I strongly encourage you to skim over that document any time you're in the mood for some light reading.
If you find a discrepancy between this answer and the ECMAScript Language Specification, please feel free to edit this answer to conform.
These are all the functions that are part of the window object.
Think of it this way. All functions are part of an object. 'this' in running code returns the object context that the function is running in. It may be the object that the function was defined under, but 'this' can be dynamically changed in code, so more accurately its the object context that the function is running in.
window is the global object in a browser, so when you're not inside a function that is part of a sub-object to window, you are in the window object context.
for instance,
var o = { test: function(){ alert(this) } }
o.test();
will alert the o object, not window.
You can call functions directly that are in the same context, which is why you can type Infinity in the console, and it returns Infinity which is part of window.
JavaScript will also look up parent objects (window in this case) to the declared object as well, so in your browser console, this works:
var o = { test: function(){ alert(Infinity) } }
o.test();

A javascript 'let' global variable is not a property of 'window' unlike a global 'var' [duplicate]

This question already has answers here:
Do let statements create properties on the global object?
(5 answers)
Closed 6 years ago.
I used to check if a global var has been defined with:
if (window['myvar']==null) ...
or
if (window.myvar==null) ...
It works with var myvar
Now that I am trying to switch to let, this does not work anymore.
var myvar='a';
console.log(window.myvar); // gives me a
let mylet='b';
console.log(window.mylet); // gives me undefined
Question:
With a global let, is there any place I can look if something has been defined like I could with var from the window object?
More generally:
Is var myvar='a' equivalent to window.myvar='a'?
I hear people say that at the global level, let and var are/behave the same, but this is not what I am seeing.
I hear people say that at the global level, let and var are/behave the
same, but this is not what I am seeing.
Eh, yes and no. To answer your question, in the large majority of cases let and var are the same when declared globally, but there are some differences.
To explain: A global environment record is where JS keeps all the logic and memory values for the code in play. However, this global environment record is really a composite encapsulating an object environment record and a declarative environment record.
Some more explanation:
A declarative environment record stores the bindings in an internal data structure. It's impossible to get a hold of that data structure in any way (think about function scope).
An object environment record uses an actual JS object as data structure. Every property of the object becomes a binding and vice versa. The global environment has an object environment record whose "binding object" is the global object. This would be the Realm, which in most cases is the window object.
So, per the ECMA spec, only FunctionDeclarations, GeneratorDeclarations, and VariableStatements create bindings in the global environment's object environment record.
All other declarations (i.e const and let) are stored in the global environment's declarative environment record, which is not based on the global object. They still declare a variable, but are not a VariableStatement.
TL;DR: Both are still global, but vars are stored in the window object, while lets are stored in a declarative environment that you can't see (just like you can't access a variable in a function scope from outside of the function). When declared globally, both statements are pretty much identical in use.

Over how much of its enclosing scope does a (javascript) closure close?

When I have some function that uses variables from its enclosing scope(s) and use that function outside of this scope (these scopes), then this is called a closure.
Is there any specification about over "how much" of its enclosing scope(s) a function has to close? (Or, put differently, over "how less" it absolutely needs to close?)
Consider:
function Outer() {
var bigGuy = createSomethingHuge();
var tinyNumber = 42;
return (function () { /* CONTENTS */ });
}
Or even:
function Layer1() {
var bigOne = somethingHugePlease();
var Layer2 = function() {
var bigToo = morePlease();
var Layer3 = function() {
var huge = reallyHuge();
var tiny = 42;
return (function () { /* CONTENTS */ });
};
return Layer3();
};
return Layer2();
}
Which of these variables does the final returned function close over? Does it depend on the contents of that final function (eval ...?)?
I'm mostly interested into whether there is some kind of specification for these cases, not so much about the behavior of some specific implementation.
I'm mostly interested into whether there is some kind of specification for these cases
The ECMAScript specification does not really detail this. It simply says that a function closes over the whole lexical environment which includes all variables in all parent scopes, organised in so-called environment records.
Yet it does not specify how an implementation should do garbage-collection - so engines do have to optimise their closures themselves - and they typically do, when they can deduce that some "closed over" variable is never needed (referenced). Specifically, if you do use eval anywhere in the closure, they cannot do that of course, and have to retain everything.
not so much about the behavior of some specific implementation
Regardless, you'll want to have a look at How JavaScript closures are garbage collected, garbage collection with node.js, About closure, LexicalEnvironment and GC and How are closures and scopes represented at run time in JavaScript
The scope chain of a nested function contains references to activation objects of all outer functions whose execution resulted in definition of the nested function. These activation objects store ALL values in place when the outer function call returned and continue to exist because they are in a scope chain.
So a closure, by definition, captures ALL variable values in scope. eval("typeof bigGuy"); within 'function () { /* CONTENTS */ } should demonstrate this.
The ECMA standards probably* cover this (if you are writing a javascript engine and have the time). A solution may be to set large sized variables to undefined when their value is no longer required.
*Based on reading ECMA 3.61 ten years ago. The computer science term "closure" did not appear in the standard. The production of closures has to be deduced by the reader as an implicit consequence of how nested function scope chains are constructed - which is in the standard. Scope chains comprise the currently executing function's activation object, outer functions' activation objects in reverse order, followed by the global object. The scope chain cannot be modified in user code.

javascript function object's [[scope]] property?

ok this is some code
function myFunc(){
var myvar = 8;
function myFunc2(num){
alert(myvar+num);
}
myFunc2(2);
}
myFunc();
i want to clear my mind so pls correct me if am wrong
i have read allot of articles in stack overflow already but i want to know i understand it well or should i read more.
to my understanding what happens behind the scene is thatin global execution context there it creates function object with the namemyFunc` and its [[scope]] property assigned to global variable object.
and when i call myFunc it creates its own execution context and activation object where all of the function's arguments and function declaration is initialized before any line by line code execution.
when inner function object is created it's internal [[scope]] property is assigned the value of its outer execution context's variable object + global variable object so every function creates its own execution context but before that every function's internal [[scope]] property is assigned first.
i have read allot of articles in stack overflow already but i want to know i understand it well or should i read more.
Here are a couple of pointers based on my understanding of the specification, and based on what sounds unclear on your explanation:
The term "Activation object" was used in ECMAScript 3, but not anymore in the current version of the specification. ES5 uses the term "Lexical Environment" to denote a type (an internal type) consisting of an "Environment Record" value, and possibly a reference to an outer Lexical Environment.
Because of this reference to an outer Lexical Environment, scope can be thought of as a chain. So access to outer scopes (including the global scope) happens through that chain. (When you say that "[[scope]] property is assigned the value of its outer execution context's variable object + global variable object", it sounds like both records are copied into the current function's Lexical Environment, which is not how it happens.)
Hope this helps!

Categories

Resources