In JavaScript does hoisting occur before or after the creation of the ExecutionContext associated with the function?
I presume before, if so when?
function foo() {
bar();
var x; // When is this hoisted?
function x() {} // ...and when is this hoisted?
};
foo();
Edit: put another way, I believe a graph of objects is instantiated according to the nesting of scopes in the program code, before a single line of code is run. Is the hoisting information stored in this object graph before runtime?
The hoisting happens as part of establishing the execution context:
[[Call]]
When the [[Call]] internal method for a Function object F is called with a this value and a list of arguments, the following steps are taken:
Let funcCtx be the result of establishing a new execution context for function code using the value of F's [[FormalParameters]] internal property, the passed arguments List args, and the this value as described in 10.4.3.
Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property. If F does not have a [[Code]] internal property or if its value is an empty FunctionBody, then result is (normal, undefined, empty).
[...]
So, when a function is executed, first its execution context is created and then the function body is evaluated. How that happens is described in section 10.4.3:
Entering Function Code
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.
The hoisting happens in step 9 and is explained in detail in section 10.5. Specifically:
5. For each FunctionDeclaration f in code, in source text order do ...
[...]
8. For each VariableDeclaration and VariableDeclarationNoIn d in code, in source text order do ...
So function declarations are hoisted before variable declarations.
Related
Recently I read about the ES5 Specification, there's one confusion in Chapter-10 which is about Execution Context. More exactly, the confusion exists in 10.5[ https://ecma-international.org/ecma-262/5.1/#sec-10.5 ].
The clause 10.5 named Declaration Binding Instantiation, it explains how the component VariableEnvironment of Execution Context is generated.Where Im confused is the item-5-iii: " If existingProp .[[Configurable]] is true... ".
What's the purpose for this, why the PropertyDescriptor.[[Value]] is undefined when call [[DefineOwnProperty]] of global object, and how to prove this step with real javascript code?
Or maybe this is a mistake? Here the [[Value]] should be the declared function object?
When a function is declared on the top level, it checks to see if the property name exists on the global object first. If the property does not exist, then:
c. Let funcAlreadyDeclared be the result of calling env’s HasBinding concrete method passing fn as the argument.
d. If funcAlreadyDeclared is false, call env’s CreateMutableBinding concrete method passing fn and configurableBindings as the arguments.
Otherwise, it goes into the e. part that you're looking at:
e. Else if env is the environment record component of the global environment then: ...
So, anywhere inside that e., funcAlreadyDeclared will necessarily be true - the property is already defined, and what remains is to check to see if the property is changeable. The PropertyDescriptor.[[Value]] will necessarily return a full property descriptor, because inside e., we know that the property does exist; that block only runs if funcAlreadyDeclared is true.
On the top level, it checks if the property is configurable, and if so, sets the associated property on the global object. Eg, function foo(){} on the top level will result in window.foo being defined, and this section checks that window.foo can be defined.
Having configurable of true means:
true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.
For example, window.top is not configurable, so the [[DefineOwnProperty]] will not run:
console.log(Object.getOwnPropertyDescriptor(window, 'top'));
So, trying to declare a function named top on the top level will throw an error:
function top() {
}
Can you explain the difference between these 3 pieces of code? They seems identical to me, but the output are different.
1:
var i;
function print(){return function(){console.log(b)}};
function doSetTimeout(b){setTimeout(print(),2000);};
for(i=0;i<10;i++){doSetTimeout(i)}
2:
var i;
function print(){console.log(b)};
function doSetTimeout(b){setTimeout(print,2000);};
for(i=0;i<10;i++){doSetTimeout(i)}
3:
var i;
function doSetTimeout(b){setTimeout(function(){console.log(b)},2000);};
for(i=0;i<10;i++){doSetTimeout(i)}
The first 2 are returning b as undefined, while the 3rd is returning the expected value.
In the first two examples you gave, you aren't passing b into print(), so print has no way to find that variable by looking at its lexical parents.
The closure isn't going to occur when you pass the function value, with print as a parameter, it's going to happen wherever setTimeout() is defined and print() is actually invoked. So you're not getting access to the context you think you are.
In the last example it works anyway, because you are defining the anonymous function inside of a function being executed that already knows what b is, so b is available.
"When a given execution context encounters a function definition in the code, a new function object is created with an internal property named [[scope]] (as in lexical scope) which references the current VariableEnvironment. (ES 5 13.0-2)
Every function gets a [[scope]] property, and when the function is invoked the value of the scope property is assigned to the outer lexical environment reference (or outerLex) property of its VariableEnvironment. (ES 5 10.4.3.5-7) In this way, each VariableEnvironment inherits from the VariableEnvironment of its lexical parent. This scope chaining runs the length of the lexical hierarchy starting from the global object."
Source:
https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/
Also a good read:
http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/
How do you get the this value of a function from outside the function, without having to call it? For example, the following doesn't work, but illustrates the idea:
// window is this, currently
function foo() {}
console.log(foo.this) // would log the window object.
The MDN documentation for Function.bind() reports that bind() "creates a new function that, when called, has its this keyword set to the provided value". This implies that each function has a "this" associated with it from the ery start.
The question is whether or not that "this" is accessible from outside the function call, because presumably it's "this" reference already exists based on thos MDN docs.
Try this in your console:
var foo = function() {}
var bar = foo.bind(this)
console.log(foo === bar)
The result is false, meaning you now have two functions, not one, and each one has it's own this.
Some have mentioned that the "callsite" determines the this of a function, which doesn't seem to be true. If you run
var obj = {}
function foo() {
console.log(this)
}
function Obj(func) {
console.log(this)
func()
}
new Obj(foo)
Then the callsite for foo is inside a new Obj but it still logs the Window object.
If you run
var obj = {}
function foo() {
console.log(this)
}
foo()
foo.call(obj)
foo.bind(obj)
foo()
Then you'll notice that the this of the original foo function has not changed. Based on this fact, and the MDN docs for bind, call, and apply, we can confidently assume that the this for a Function can never be changed.
this can be changed depending on how you call the function, so, there is no real way to get it outside of the function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
No there is no way to get the value of this because this is not actually related to the function object, but to the execution context that is created when the function is called.
An execution context has the following properties:
LexicalEnvironment
Identifies the Lexical Environment used to resolve identifier references made by code within this execution context.
VariableEnvironment
Identifies the Lexical Environment whose environment record holds bindings created by VariableStatements and FunctionDeclarations within this execution context.
ThisBinding
The value associated with the this keyword within ECMAScript code associated with this execution context.
Now, when a function is called, the following steps take place:
10.4.3 Entering Function Code
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 argumentList as described in 10.5.
Notice especially
[...] a caller provided thisArg [...]
This should make clear that the value of this is provided by the caller of the function.
Examples:
When a function is called as foo(), then there is no thisArg, so it is undefined. In that case, step 2 takes place and this is bound to the global object.
However, if a function is called as foo.call(bar), then thisArg is bar and either step 3 or 4 take place, depending on whether bar is an object or not.
I hope this explains why it is not possible to get the this value of a function.
you need a little help from the function.
function foo(){
return this;
};
console.log(foo());
Variable/Lexical Environment component of execution context
Question 1:
For what VariableEnvironment component of exection context is needed?
As said in spec LexicalEnvironment component
used to resolve identifier references made by code
within this execution context.
But VariableEnvironment component used to
holds bindings created by VariableStatements and FunctionDeclarations
within this execution context.
Ok, but evaluation of PrimaryExpression:Identifier is execution with LexicalEnvironment component, not VariableEnvironment of running execution context:
Let env be the running execution context‘s LexicalEnvironment.
If the syntactic production that is being evaluated is contained in a strict mode code, then let strict be true, else let strict be false.
Return the result of calling GetIdentifierReference function passing env, Identifier, and strict as arguments.
Thus is VariableEnvironment need for bindings storage only?
Establishing function context is occuring as:
sec. 10.4.3
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.
Where at step 9 bindings add to a VariableEnvironment only. At step 5 [[Scope]] internal property indicates to outer LexicalEnvironment. Thus i have question
Question 2:
Is it true that just after creation of execution context of function code LexicalEnvironement's initial environment record contains the same bindings that environment record of outer LexicalEnvironment?
Consider the following code snippet into the global code?
Example of function code
function bar(){
var b={b:'b'}
var o={o:'o'}
}
bar();
Question 3:
Is it true that just after creation of bar execution context before the start of execution function code VariableEnvironment's environment record will be contain bar-->function bar(){ ... }, b-->{b:'b'}, o--> {o:'o'}, but LexicalEnvironment's environment record
Question 1
VariableEnvironment is the leaf of the scope chain at the start of a function. Since
all variables and functions are hoisted at the top of the current function (or global scope), it defines the scope of identifiers visible strictly inside a given function.
LexicalEnvironment extends VariableEnvironment when you use the constructs with and catch. See my other answer for more details.
Both environments are used for name resolution. LexicalEnvironment is used most of the time, except in function bodies (i.e. a function within a function), where VariableEnvironment (of the parent function) is supposed to be used instead.
As I said in my previous answer, the case is rather unfrequent and various implementations behave differently.
I'm not sure I understand what you mean by 'binding storage'.
Bindings take place when applicable (i.e parameters passing or assignment) once the names are resolved, whichever environment allowed the resolution.
Basically, the names inside a VariableEnvironment are those of local variables (bound to heap objects when the variables are assigned) and parameters (bound to the passed values when the function is called, as described in steps 8-9 of spec 10.4.3).
The names in LexicalEnvironment will be either the name of the exception context for a catch statement or the names of an object's properties for a with statement. They will be bound to their corresponding instances when the statement is evaluated, and disposed of at the end of the statement body.
For instance:
function stick_to_top (element)
{
with (element.style) { top = 0; }
}
stick_to_top (document.getElementById ("wanderer"));
binding of top will occur when the statement top = 0; is executed, during function invokation.
Name resolution will resolve top as element.top using the Lexical context of stick_to_top() enhanced by the with statement that will contain the names of all element.style properties, and resolve element as stick_to_top()'s argument using the Variable context of stick_to_top(), which contains only the name of the parameter element.
In the end, value 0 will be assigned to property style.top of the DOM object having the ID "wanderer" (assuming getElementById() found it, of course).
Now if you're up for a joke, try this :
var tip = { style:{top:1}};
var top = { style:'', invaluable_information:42};
var tap = { };
stick_to_top (tip);
stick_to_top (top);
console.log ("tip %o top %o", tip, top);
stick_to_top (tap);
result:
tip [object Object] top 0
SCRIPT5007: Object expected
tip behaves just like a regular DOM object since we defined a style.top property for it
tap does not have a style property, so tap.style is undefined and the interpreter throws an error when trying to process the with statement.
top is the unlucky one. It does have a style property so the with statement is happly creating an empty Lexical environment. Now identifier top is nowhere to be found inside stick_to_top(), so name resolution goes back to global context where it happily finds an unsuspecting top variable. Inevitable tragedy ensues...
Question 2
Both Lexical and Variable environments are local to a context. The scope is made of a chain of environments, i.e. when resolving a name, if the identifier could not be found in the current environment, parent environments are tried in succession until you reach the toplevel environment where identifiers are considered properties of the global object.
(since you seem to be interrested mostly in variables, I leave aside the function prototype scope for the sake of concision)
So the answer to your question is no. In your example, the lexical environment of the toplevel is the collection of all global variables (i.e. the properties of the window object), while the lexical environment of foo() is identical to its variable environment, containing only the names of the two locals b and o.
Question 3
It will just contain b-->{b:'b'}, o--> {o:'o'}
bar-->function bar(){ ... } will be in the toplevel's lexical context.
the bar identifier will be a synonym of window.bar.
(here again, think of a JavaScript program being enclosed in an implicit with (window) statement).
I do know that in javascript, when you use "this" keyword inside a function, then "this" would refer to the 'owner' of that function according to Quirksmode website. Therefore when we have a function and we use "this" inside it, then "this" refers to the global (window) object.
I am a little confused on how "this" works, for example in the code below, "this" then should be able to resolve x since x is pretty much a property of global object (in this case window). But this.x in this case alerts "undefined" instead of the x value.
var x = "Global";
function foo(){
alert(this.x); //undefined
};
foo();
I then tried some other things too:
function bar(){
function foo(){
alert(this); //[Object DOMWindow]
};
foo();
};
bar();
If my understanding is correct, then 'this' should refer to bar() in that second case since it is the owner of foo(), but why is that it instead still refers to the global object?
Can someone explain what is the correct theory regarding "this" keyword?
You've got the wrong end of the stick. The value of this depends on how the function is called, not how it is defined.
If you call window.foo() then (inside foo) this will be window
If you call bar.foo() then this will be bar (although you need to copy foo so it is a property of bar first)
If you call baz.bar.foo() then this will be bar (you only ever get the parent object via this)
If you call foo.call(bar) then this will also be bar as call lets you override this
If you call new foo() then this will be the new object being created
The default object is window, so if you just call foo() then that is the same as window.foo().
It doesn't matter what scope the function is defined in.
Summarizing your question, you ask why in your first snippet, this.x is undefined:
var x = "Global";
function foo(){
alert(this.x); //undefined
}
foo();
It doesn't make sense at all, the this value should refer to the global object -if your code were on strict mode, you would get a TypeError, since this by itself would be undefined-.
The only way I think where this.x could be undefined, is in the case that the variable declaration of x was made within a function.
Check the two following examples: 1 and 2, it's exactly the same code, the difference is that the second one, the code is wrapped in an onload event handler, so the x variable doesn't exist in the global scope (window.x is undefined)...
Yes, this is always the owner of the function being executed and the best answer about this subject is more than you ever wanted to know about this
var x = "Global";
function foo(){
alert(this.x); // alerts "Global" for me
};
As for the bar(), it is a standalone function and this will be bound to the "global" object as described in the answer linked above, which is your case is the DOMWindow
If you really wish to learn how this works, then read the ECMAscript 262 specs from the section 10.3 Execution Context and onwards.
Here is what it says in section 10.4.3:
10.4.3 Entering Function Code
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.