This question already has answers here:
What is the difference between `new Object()` and object literal notation?
(12 answers)
Closed 9 years ago.
I want to understand why is the difference in performance when both does same thing?
Benchmark
Performance of {} can be explained as :
{} is the literal for object in Javascript, and literals are evaluated faster.
As an added bonus, literals take up less space in your code, so the overall file size is
smaller.
The end result of literal code is the same as the new Object() code, but it is executed faster in almost all browsers (Firefox 3.5 shows almost no difference).
As the number of object properties and array items increases, so too does the benefit of using literals.
Object Literals {} are executed faster because of scope managing mechanism in Javascript
When JavaScript code is being executed, an execution context is created. The execution context (also sometimes called the scope) defines the environment in which code is to be executed.
A global execution context is created upon page load, and additional execution contexts are created as functions are executed, ultimately creating an execution context stack where the topmost context is the active one.
Each execution context has a scope chain associated with it, which is used for identifier resolution. The scope chain contains one or more variable objects that define in-scope identifiers for the execution context.
The global execution context has only one variable object in its scope chain, and this object defines all of the global variables and functions available in JavaScript.
When a function is created (but not executed), its internal [[Scope]] property is assigned to contain the scope chain of the execution context in which it was created (internal properties cannot be accessed through JavaScript, so you cannot access this property directly).
Later, when execution flows into a function, an activation object is created and initialized with values for this, arguments, named arguments, and any variables local to the function. The activation object appears first in the execution context’s scope chain and is followed by the objects contained in the function’s [[Scope]] property.
During code execution, identifiers such as variable and function names are resolved by searching the scope chain of the execution context.
Identifier resolution begins at the front of the scope chain and proceeds toward the back. Consider the following code:
function Add(n1, n2) {
this.n1 = n1;
this.n2 = n2;
this.val = this.n1 + this.n2;
}
var result = new Add(5, 10);
When this code is executed, the add function has a [[Scope]] property that contains only the global variable object.
As execution flows into the add function, a new execution context is created, and an activation object containing this, arguments, n1, and n2 is placed into the scope chain.
Below Figure , “Relationship of execution context and scope chain” illustrates the behind-the-scenes object relationships that occur while the add function is being executed.
Inside the add function, the identifiers num1 and num2 need to be resolved when the function is executing.
This resolution is performed by inspecting each object in the scope chain until the specific identifier is found.
The search begins at the first object in the scope chain, which is the activation object containing the local variables for the function.
If the identifier isn’t found there, the next object in the scope chain is inspected for the identifier. When the identifier is found, the search stops.
In the case of this example, the identifiers num1 and num2 exist in the local activation object and so the search never goes on to the global object.
Understanding scopes and scope chain management in JavaScript is important because identifier resolution performance is directly related to the number of objects to search in the scope chain.
The farther up the scope chain an identifier exists, the longer the search goes on and the longer it takes to access that variable; if scopes aren’t managed properly, they can negatively affect the execution time of your script.
Related
I am new to JS and confused with how variables are put into stack and heap. For example,
let num = 5;
let obj = {};
function showNum() {
let num2 = 8;
let obj2 = {}
console.log(num2);
}
showNum();
As you can see from the above code, I created both global and local variables and would like to ask some questions on how variables are put into stack and heap.
Firstly, as you can see there are global variables num and obj. The question is:
Are they attached to stack(num) and heap(obj) of global execution context since they are not local variables?
Secondly, there are local variables inside showNum() function. The question is:
When the function is executed and is pushed into call stack, will num2 and obj2 (I mean reference of obj2 is put into callstack) variables are put into callstack as well? Since I think stack = callstack.
Lastly, is it true that after showNum() is popped of the callstack, num2 variable is also removed from the stack except for obj2 which is removed by garbage collector?
Globals
Conceptually (e.g., in terms of the specification), global variables are held as bindings in the global environment record. A binding is a combination of a name, current value, and a couple of flags related to the binding (whether it's mutable and whether it's initialized).
Practically, of course, the JavaScript engine can store them in any way it likes provide it behaves according to the semantics of the specification.
The details will be down to the specifics of the JavaScript engine, but it seems likely that global bindings would be held in the heap.
Locals
Conceptually, locals are also held in an environment record, one that's created for the call to the function the locals relate to and which may or may not be reclaimed when the function call terminates. I go into some detail on that in my answer here, but briefly, if any function created within the function being called continues to exist after the function returns, conceptually it has a reference to the environment record (more accurately to the lexical environment object the record relates to), which is why functions that close over locals can continue to access those locals after the function containing them returns.
Practically, again, the JavaScript engine can do this any way it likes provided that it conforms to the semantics in the specification, and modern engines are highly optimized. They'll put locals on the stack when possible (including objects). In cases where the locals are referenced by closures created during the function call that survive the termination of the function, the engine will either put them in some kind of environment record object in the first place or move them there from the stack.
Your specific questions:
Are (the globals) attached to stack(num) and heap(obj) of global execution context since they are not local variables?
They're bindings in the environment record for the lexical environment of the global execution context. How that relates to stack vs. heap is an implementation detail.
When the function is executed and is pushed into call stack, will num2 and obj2 (I mean reference of obj2 is put into callstack) variables are put into callstack as well? Since I think stack = callstack.
Again, this is an implementation detail as discussed above. Note that it's common for the same stack to be used for both locals and return addresses (and other call metadata), but that doesn't have to be the case. It's up to the implementation.
Lastly, is it true that after showNum() is popped of the callstack, num2 variable is also removed from the stack except for obj2 which is removed by garbage collector?
Conceptually: Since showNum doesn't create any functions that continue to exist when it returns, its lexical environment and associated environment record are both released when it returns.
Practically, again, it's down to the implementation. In an optimized engine, it's possible that num2, obj2 (which contains the reference to the object), and the object are all stored on the stack (the object is quite small, after all), and so popping the stack reclaims all their memory immediately. Or it might be that num2 and obj2 are on the stack but the object obj2 refers to is in the heap, and so popping the stack just removes num2 and obj2 leaving the object with no outstanding references, meaning it's eligible for garbage collection. It's implementation-specific.
Having understood the basics of Closures there is one doubt that's still haunting me :
Where does enclosing function reside post its execution or after returning closure function ?
I believe functions reside in stack data structure and knocked off the top of stack once function finishes its execution / returns any value.
But in Closures, inner function will still have to access to the state of Enclosing function, how ?
function sayHello(name) {
var text = name + ' !!!'; // Local variable
return function(wish) { console.log(wish + ', ' +text); }
}
var say = sayHello('Bob');
say('Hey');
say('Hello');
Where is sayHello present once it returns a function, as its removed from function stack frame ?
This is one very good article on this.
https://dmitryfrank.com/articles/js_closures
Scope chain
When any JavaScript code is executing, it needs some place to store its local variables. Let's call this place as a scope object (some refer to it as a LexicalEnvironment). For example, when you invoke some function, and function defines local variables, these variables are saved on the scope object. You can think of it as a regular JavaScript object, with the notable difference that you can't refer to the whole object directly. You can only modify its properties, but you can't refer to the scope object itself.
This concept of scope object is very different from, say, C or C++, where local variables are stored on stack. In JavaScript, scope objects are allocated in heap instead (or at least they behave like this), so they might stay allocated even if function already returned. More on that later.
As you might expect, scope object might have parent. When the code tries to access some variable, interpreter looks for the property of current scope object. If the property doesn't exist, interpreter moves to the parent scope object, and looks there. And so on, until the value is found, or there's no more parent. Let's call this sequence of scope objects as a scope chain.
The behavior of resolving a variable on scope chain is very similar to that of prototypal inheritance, with, again, one notable difference: if you try to access some non-existing property of regular object, and prototype chain doesn't contain this property either, it's not an error: undefined is silently returned. But if you try to access non-existing property on the scope chain (i.e. access non-existing variable), then ReferenceError occurs.
In JavaScript: Understanding the Weird Parts lexical environment is explained as the scope of your code while execution context is a collection of lexical environments, and that it includes stuff beyond your written code.
The descriptions of these terms still sound overlapping in functionality and it's unclear as to what execution context does or how it does it.
The best way to think of an execution context is as a stack frame, while lexical environments are indeed the scopes.
The respective spec chapters (§8.1 Lexical Environments and §8.3 Execution Contexts) explain:
Execution contexts contain the current evaluation state of code, a reference to the code (function) itself, and possibly references to the current lexical environments.
Execution contexts are managed in a stack.
Lexical environments contain an environment record in which the variables are stored, and a reference to their parent environment (if any).
Lexical environments build a tree structure.
With every change of the execution context, the lexical environment changes as well. However the lexical environment may change independently from that as well, for example when entering a block.
Execution Context & Execution Context stack : Execution context is the internal javascript construct to track execution of a function or the global code. The js engine maintains a stack - execution context stack or call stack, which contains these contexts and the global execution context stays at the bottom of this stack. And a new execution context is created and pushed to the stack when execution of a function begins. A particular execution context tracks the pointer where statement of the corresponding function is being executed. An execution context is popped from the stack when corresponding function's execution is finished.
Lexical Environment : it's the internal js engine construct that holds identifier-variable mapping. (here identifier refers to the name of variables/functions, and variable is the reference to actual object [including function type object] or primitive value). A lexical environment also holds a reference to a parent lexical environment.
Now, for every execution context -- 1) a corresponding lexical environment is created and 2) if any function is created in that execution context, reference to that lexical environment is stored at the internal property ( [[Environment]] ) of that function. So, every function tracks the lexical environment related to the execution context it was created in.
And every lexical environment tracks its parent lexical environment (that of parent execution context). As a result, every function has a chain of lexical environments attached to it. [Note: in js a function is an object, creating a function by a statement means creating an object of type Function. So like other objects, a function can hold properties both internal and user defined]
The js engine search any variable or function identifier in the current lexical environment, if not found it searches the chain attached to the enclosing function. (for global code this chain does not exist). So, you understand how scoping of variables and functions are maintained. The concept of closure is also backed by, this chain (not a standard term, I just used it to ease the understanding). When a function instance is passed to another function as an argument, to be used as callback, it carries it's chain with it (sort of).
Note: the answer is based on what I learned from 'Secrets of the Javascript Ninja, 2/e'
The answer marked above likened the Execution Context to a Stack Frame. But the Execution Context in JavaScript is no ordinary Stack Frame.
In the global Execution Context, JavaScript Engine creates two things for you, a Global Object (an Object is a collection of name/value pairs) and a special variable called 'this'. In browsers, the Global Object is a window object. In NodeJS, the global object is something else. The point is there is always a global object.
When you create variables and functions that are not inside other functions, those variables are in the global context and thus get attached to the global object, which in the case of browsers is the window object.
hello = 'hello world'
> "hello world"
window.hello
> "hello world"
The execution context in JavaScript is created in two phases. The first phase is the Creation Phase. In the global execution context, the Global Object is setup and in memory, the special variable 'this' is setup, points to Global Object and is in memory, and there is an Outer Environment (Lexical Environment). As the Parser begins the Creation Phase of the execution context, it first recognizes where you created variables and functions. So the Parser sets up memory space for variables and functions. This step is called 'Hoisting'. Hence, before your specific code is executed line by line, the JavaScript Engine already set aside memory space for the variables and functions you created in the global Execution Context:
console.log(a);
console.log(b());
console.log(d);
var a = 'a';
function b(){
return 'called from b';
}
function c(){
d = 'd';
}
> undefined
> called from b
> Uncaught ReferenceError: d is not defined
In the above example, since the variable 'a' and the function b() were created in the global Execution Context, memory space is allocated for them. Note though that the variables are not initialized, just declared with an undefined value. This is not the case for functions. Functions are both declared and initialized, so both the identifier and the actual code of the function is stored in memory. Also note that since d (even though it is not specified with var, let or const) is not in the global Execution Context, no memory space is allocated for it. And so an exception is raised when we try to access the d identifier.
Now if we invoke c() before we reference the d variable, then a new execution context is evaluated (which is not the global Execution Context) and then d will be in memory (in that new execution context, the this keyword will point to the global object since we did not place 'new' before the function invocation and so d will be attached to the global object):
console.log(a);
console.log(b);
console.log(c());
console.log(d);
var a = 'a';
function b(){
return 'called from b';
}
function c(){
d = 'd';
return 'called from c';
}
> undefined
> b() { return 'called from b' }
> called from c
> d
One final point about the Creation Phase of the Execution Context. Since 'hoisting' occurs, order of function definitions or variables do not matter in terms of lexical scoping.
The second phase of the Execution Context is called the Execution Phase, and this is where assignments occur. The JavaScript engine begins parsing your code. So that is when variables will be assigned a value. In the first phase, they were just declared and stored in memory with an undefined value. 'undefined' is a placeholder which is JavaScript's way of saying 'I don't know what this value is yet'. This is the same placeholder JavaScript gives when you declare a variable without assigning it a value. Consequently, it is not a good idea to rely on JavaScript's 'Hoisting' feature. Simply put, do not use a variable in global Execution Context (or in any execution context) before it is declared with var, const or let. So it is always better to do this:
var a = 'a';
function b(){
return 'called from b';
}
console.log(a);
console.log(b());
Do not confuse yourself with the JavaScript built-in data type 'undefined' vs an undefined exception raised by the parser. When a variable is not declared anywhere and you try to use it, the JavaScript Engine will raise an exception 'Uncaught ReferenceError: [variable] is not defined'. JavaScript is saying that the variable is not in memory. This is different then initializing a variable with the undefined data type.
In addition to the global Execution Context, function invocation creates a new Execution Context. First, in the below example, a global Execution Context is created. The Creation Phase of the global Execution Context will be handled by the JavaScript Engine. It will create a Global Object (window in the case of browsers), and it will create a special variable 'this' and point it to the Global Object. Then the b and a function will be attached to the Global Object. Memory space will be allocated for them, and since they are functions, their code will be stored in memory as well. If there were any variables, they will be stored in memory too, but they will not be initialized and thus stored with the data type undefined. Then the Execution Phase begins. Since JavaScript is single-threaded, it executes line by line. During this time, it encounters a(). It sees the '()' and knows it must invoke the function a. A new Execution Context is created and placed on the Execution Stack. As you probably know, the stack data structure is last in first out. An Execution Context is pushed onto the Execution Stack, and when it is finished, it is popped from the stack. Whatever context is on top, that is the Execution Context that is currently running.
function b(){
}
function a(){
b();
}
a();
The a() Execution Context will be stacked on top of the global Execution Context. It will have its own memory space for local variables and functions. It will go through the Creation Phase and Execution Phase of the Execution Context. During a() Execution Context's Creation Phase, since it did not declare any variables or functions, it does not allocate space for any new variables or functions. If it did declare any local variables or functions, it will go through the same 'Hoisting' process as is the case in the global Execution Context. Also, a new special 'this' variable is created for that particular function. Note though if you invoke the function without the new keyword, then 'this' will still reference to the global object, which is the window object in browsers.
Then, it moves on to the Execution Phase. Here it invokes the b() function, and now a third Execution Context is created. This is the b() Execution Context. It goes through the same Creation and Execution Phase as the other Execution Contexts'.
When b() finishes, it is popped off the stack, and then when a() finishes, it will be popped off the stack, and then we return back to the global Execution Stack. Importantly, each execution context stores a pointer to where it left off when it invoked a function and hence created a new execution context. So when b() finishes, a() returns to the statement wherein it invoked b(). And then continues execution on the next statement in that execution context. Again, remember, JavaScript is single-threaded, so it executes line by line.
The key about the Lexical Environment is it has a link to any Outer Environment (i.e. its scope chain), so it is used to resolve identifiers outside the current Execution Context. Ultimately, a corresponding Lexical Environment is created for every Execution Context. The Lexical Environment cares about where the code sits physically (lexically) in your application.
Execution Context
Execution Context is created every time, the JS engine calls a function. They stays in the call stack.
Lexical Environment
The lexical environment includes the scopes that are present at a certain point in time. Every execution context has its own lexical environment.
Check the image and see the scope and the call stack section on the right side of the image:
The call Stack section contains two execution context (test1 and anonymous).
The scope section contains the lexical environment of the test1 execution context.
test1 lexical environment has three objects Global, Local, and Block when the JS engine is executing line no 10.
As said in sec 10.4.3
The following steps are performed when control enters the execution
context for function code contained in function object F, a caller
provided thisArg, and a caller provided argumentsList:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
Else set the ThisBinding to thisArg.
Let localEnv be the result of calling NewDeclarativeEnvironment passing the value of the [[Scope]] internal property of F as the
argument.
Set the LexicalEnvironment to localEnv.
Set the VariableEnvironment to localEnv.
Let code be the value of F‘s [[Code]] internal property.
Perform Declaration Binding Instantiation using the function code code and argumentsList as described in 10.5.
Consider the following code snippet:
function foo(){
var a={p:'p'};
o={c:'c'};
}
Thus we have the following:
Code of our function isnt a strict code
thisArg is null hence, ThisBinding set to the global object
---
---
I dont understand what bindings will be contains environment record represented by [[Scope]] internal property.
Set the LexicalEnvironment to environment which geted at step 5.
Set the VariableEnvironment to environment which geted at step 5.
Perform declaration binding instatiation.
At step 8 bindings are created in the VariableEnvironment, but not in LexicalEnvironment. But in sec 10.3 said that
When an execution context is created its LexicalEnvironment and
VariableEnvironment components initially have the same value.
Question:
Why just after creation of execution context LexicalEnvironment and VariableEnvironment is still equal in my case above?
I am not sure I understand your question, but this is how I understand sec 10.4.3 :
steps 1 to 4 are dealing with the value of this. Basically, in strict mode, this will be left to a null or undefined value instead of defaulting to the global object (window in case of a browser). This covers the cases when a function is not invoked through usual object or event handler mechanisms.
step 5 to 7 mean that a new naming environment is created each time you enter a function.
It describes the creation of this environment, which is linked to the previous one to form the current name scope.
For each new function, two environments are co-existing.
When a name is resolved, Lexical environment is searched first, then Variable environment. If both searches fail, the process is repeated at the upper level of the environment chain, until the 'catch-all' global scope is encountered. In this scope, all identifiers are handled as properties of the global (window) object. You can picture it as the whole code being enclosed in a with (window) block.
Lexical environment can be seen as a temporary augmentation of the variable scope.
Lexical and Variable environments are functionnally identical until you alter the lexical environment with two specific statements: with or catch. It does not mean they are implemented as identical data structures.
In terms of implementation, you could imagine the lexical environment as an empty list and the variable environment as a list containing all local variable and parameter names.
When a catch or with statement is encountered, the lexical list is populated with new names that will take precedence over the ones stored in the variable list.
catch will simply make its argument available for name resolution (i.e. allow you to reference the exception parameter). No big deal since the new name is just as explicit as a function parameter.
with is a rather more dangerous beast. It will create a new environment with the names of all properties of the object passed as its argument. The scope will consist of the chain of variable environments plus this new lexical environment.
Here the new names available for resolution are 'hidden' inside the object.
For instance:
var a = 'a', b = 'surprise!', o = {a:'a'};
with (o) { a = b; }
console.log (a+" "+b+" "+o.a);
will yield
a surprise! surprise!
a is resolved as o.a since o contains a property named a.
b is not found inside the lexical environment and thus the current variable environment is tried and variable 'b' is found.
This is a pretty dangerous mechanism, because if you believe an object contains a given property while it actually doesn't, you will instead reference a variable outside the current scope.
For instance, a simple typo like this:
with (element.style) {leftt = '10px';}
will set the window.leftt property to '10px', unless you happen to have declared a variable named leftt somewhere in the current scope.
Now if you give silly names like 'i' or 'j' to your object properties, chances are you will clobber a random loop index somewhere up the scope chain while believing you are setting the property of an object.
step 8 describes the parameters binding once the function scope is established. Basically, the parameters are bound with the values and their names are added to the variable environment.
The whole point of keeping two separate environments is that the hoisting mechanism always uses the variable environment chain as a scope.
The idea is that a variable or function should behave as if it had been declared at the top of the current scope block, so for instance a function declared inside a with block should not resolve its names with the object properties exposed by the with statement.
Frankly this is a rather moot point, since ECMA spec does not allow function declarations inside blocks, although most implementations do, with varrying results.
Now for your example:
function foo(){
var a={p:'p'};
o={c:'c'};
}
Your function does not contain any with or catch statements, so the scope chain inside 'foo()' is just a list of two variable environments :
global (a bunch of DOM objects all seen as properties of 'window')
function foo (var a)
once you call foo(),
a will resolve as foo's local variable, will be created as an object with the property p of value 'p' (and garbage collected as soon as you leave foo(), unless you manage to reference it from a persistent variable).
o will not be found in foo's variable environment, so it will be caught by the 'catch-all' global scope and thus resolved as a (new) property of the window object. It will create a window.o.c property with the value 'c'.
Does that answer somewhat to your question?
Compare this code1:
somevar = 5;
delete window.somevar;
alert(typeof somevar) //=> undefined, so deleted
to this code:
var somevar = 5;
delete window.somevar;
alert(typeof somevar) //=> number, so NOT deleted
See it in action here
Now in the first block, somevar is deleted, in the second block it's not. The only difference is using the var keyword in the second block. Both blocks run in the global scope.
Can this be explained?
1 the code can't be tested in a chrome-console or firebug, and not in jsfiddle either. In those environments all code is evalled, and in evalled code delete works on anything that is the result of eval (see more about that). In IE < 9 delete window[anything] is not allowed anyway.
What you're seeing is an aspect of the fact that the global object (window, on browsers) is a conflation of two different things which are distinct everywhere except the global execution context.
In the first block, someVar is a normal property of the window object. Properties can be removed via delete.
In the second block, someVar is a property of the binding object of the variable context of the global execution context — which is also window. You cannot delete properties the binding object receives in its role as the binding object (even though you can delete properties it receives in other ways). That is, you cannot delete variables declared with var (and a few other things that are added the same way).
(Sorry, not my terminology; it comes from the spec, which features some very fun language indeed.)
It's only the global execution context where we have this conflation of concepts. The variable binding object for other execution contexts (function calls, for instance) is still a very real thing (and crucial to proper functioning of closures), but there's no programmatic way to directly access it. In the global execution context, though, it's the global object, which of course we can access.
It helps to understand this if we look at functions first, and then look at the global execution context. when you call a function, these things happen:
Set this to point to the object designated by the call (the value of this is usually implicitly set, but there are ways to set it explicitly).
Create an execution context for this call.
Create a variable context for that execution context.
Create a binding object for that variable context.
Add the function's name, if it has one, to the binding object as a property referring to the function.
Add the arguments property to the binding object, referring to the pseudo-array of arguments to the function.
Add any named arguments declared in the function definition as properties of the binding object, referring to their entries in the arguments.
Add the names of of any variables declared via var statements (anywhere in the function body) as properties of the binding object, initially with the value undefined.
If there are named functions declared within the function, add their names as properties of the binding object, referring to those functions.
Put the binding object at the top of the scope chain (more below).
...and then step-by-step execution of the code in the body of the function begins. Any var statements with initializers (e.g., var a = 5; rather than just var a; are treated as assignment statements (a = 5;) when the execution point reaches them.
Throughout the above, whenever a property is added "to the binding object", it's added with a flag indicating that it cannot be deleted. This is why vars (and the names of declared functions, etc.) can't be deleted.
Any unqualified reference is looked up via the scope chain. So when you refer to a in your code, the first place the interpreter looks is the binding object at the top of the scope chain. If it has a property called a, that's what gets used; if not, we look at the next link down the scope chain and use that property if we find it; and so on until we run out of links on the scope chain. The global object is the bottommost link of that chain (which is why global variables work).
So what's different about the global context? Well, very little, actually. Here's the sequence (roughly):
Create an execution context for this call.
Create a variable context for that execution context.
Create a binding object for that variable context.
Set this to point to the binding object; that makes it the global object.
Set some default properties on that object as defined by the environment (in browsers, for instance, the property window is added to the object, referring to itself).
...and then we basically pick up with step 8 in the function stuff:
Add the names of of any variables declared via var statements (anywhere in the global scope) as properties of the binding/global object, initially with the value undefined.
If there are named functions declared within the global scope, add their names as properties of the binding/global object, referring to those functions.
Put the binding/global object at the top of the scope chain (more below).
...and start step-by-step execution of the code (again with var initializers becoming assignments).