Scope chain first looks to __parent__ or to __proto__? - javascript

Here I found information hot to works scope chain:
...before we go to the parent link, first proto chain is
considered.
Notice, that not in all implementations the global object inherits
from the Object.prototype. The behavior described on the figure (with
referencing “non-defined” variable x from the global context) may be
tested e.g. in SpiderMonkey.
I use Firefox browser for testing, but, when I set global variable x, and set to Object.prototype property x and do a() I've got 4. Why, if first we go to proto?
var x = 1;
Object.prototype.x = 2;
var a = function () {
y = 3;
return this.y + this.x;
};
a.x; // 2
a(); // 4

You should've cited the beginning of that paragraph, not the end:
At code execution, a scope chain may be augmented using with statement and catch clause objects.
So what your sentence refers to are only object environment records - scope objects in which variables live. Those are typically imaginary, described for specification purposes only (and can only be observed in Rhino), but the with statement makes an exception and prepends an actual JS object to the scope chain.
If you check out the example, you will find the with statement right there. The gist:
Object.prototype.x = "inherited object property";
var x = "parent scope variable";
with ({}) {
alert(x); // you bet what it yields
}
When I set global variable x, and set Object.prototype.x property, why doesn't it get the prototype value?
By using this in a function that is called plainly (a()), you are referring to the global object. It is indeed the object for the object environment record of the global scope, which means that all global variables live there as properties.
Now why does accessing x on that object (regardless whether by variable x or property this.x) bring up 1 not 2? Because the global variable with the value 1 is an own property of the object. The prototype chain will only be traversed if the property is not already found!

Related

Scope chain look-up vs prototype look-up - Which is when

If a variable is not available in a function when it's needed, then it's being looked for in the scope chain (which is a closure), but other times it's being searched for in the prototype chain. I am trying to wrap my head around which is happening when. I was wondering if someone could kindly clear the mist for me, or refer me to some literature discussing this topic specifically.
For example, would I be right saying that:
- Objects and therefore public variables tied to the context (this)are always looked up in the prototype chain?
- Private variables are always looked up in the scope chain (i.e. chain of functions in the execution context)? - Are there any cases when the program is looking in both/either?
I tested three different scenarios(scope chain look-up, prototype look-up and no look-up), but unfortunately It haven't helped enough to get to the bottom of this.
var Food = function(){
var t = 1; // for closure
this.timeToPrepare = function(){ // Scope chain lookup
console.log(t * 3);
};
this.timeToMake = function(){ // This is looked up in the prototype chain
console.log(this.t * 3);
};
this.timeToEat = function(t){ //No lookup
console.log(t * 3);
};
};
Food.prototype.t = 2;
(function(){
var pizza = new Food;
pizza.timeToPrepare(); //3
pizza.timeToMake(); //6
pizza.timeToEat(3); //9
})();
Thanks!
Variables are looked up on the scope chain, starting with the current execution context and going up the tree of enclosing execution contexts.
Properties are looked up firstly on the base object, then on that object's [[Prototoype]] chain (i.e. its internal prototype).
So if you do:
foo
foo will be treated as a variable and looked up on the scope chain. Variable names are never qualified, you can't direct them to a specific execution context to be looked up in. If there are two variables on the scope chain with the same name, you can only access the one that is first encountered when going along the chain (there is a way around this specifically for global variables), e.g.
var a = 'global a';
function foo() {
var a = 'local a';
return a;
}
console.log(foo()); // local a
In the above, a within the function resolves to the local variable a. In the case of global variables, they are made properties of the global object so you can access them even if they are "shadowed" by a same named local property, e.g.
function foo() {
var = 'local a';
// this will reference the global object
return this.a;
}
console.log(foo()); // global a
In contrast, property names are always preceded by a base object on which they are looked up (as in the example above, where this references the global object), e.g.
foo.bar
will be split into foo and bar. Firstly, foo will be resolved on the scope chain and, if found, property resolution will try to find a bar property. So for properties, you can direct which object the property is looked up on. So if there are two objects with a same named property, you can look up both properties as long as both objects are in scope.
So the first part of any reference is treated as a variable, the subsequent parts are treated as properties. Except when with is used, but that is discouraged. Don't go there.
But for completeness… with places the specified object on the start scope chain so that variables are first looked up as properties of that object before using the scope chain, so you can do:
var cos = function(arg){return 'my cos function: ' + arg};
function foo() {
// cos is resolved on the scope chain
console.log(cos(0.5)); // my cos function: 0.5
with (Math) {
// cos is first resolved as a property of Math, and only on the
// scope chain if not found there
console.log(cos(0.5)) // 0.8775825618903728
}
}
foo();

mark and sweep in javascript(context variable)

i am reading Professional JavaScript for Web Developers
i got problem when reading "When the garbage collector runs, it marks all variables stored in memory. It then clears its mark off of variables that are in context and variables that are referenced by in-context variables."
i know when the object could not be reached by any variables, the memory associated would be reclaimed.
What does "variables that are in context" mean? Are they variables that could be found in the scope chain? But what about the "variables that are referenced by in-context variables"?
i am confused.
I'm assuming it's to avoid accidentally deleting variables used in a closure. In javascript, just like any other functional language, just being unreachable is not enough to tell you weather you should delete an object.
Take for example the following code:
function a () {
var x=0;
return function () {
alert(x++);
}
}
var b = a();
// at this point, the instance of `x` created by calling `a` is
// no longer reachable but we are still using it in the closure.
If we follow just the "unreachability" rule then the closure created would lose the variable x.
Consider this:
(function(){
var sobriety = [];
window.inception = function() {
var i = 0,
j = 0,
inner_level = { i: i },
level = { level: inner_level },
food = {};
return function() {
var new_level = {
level: level.level
};
new_level[i] = 'step ' + i;
new_level.level.i = i;
sobriety[i++] = new_level;
};
};
window.show_my_sobriety = function() { console.log(sobriety); };
})();
var agent = inception();
agent(); agent(); agent();
show_my_sobriety();​
JS Fiddle.
I admit this example is somewhat sophisticated, but I just had to make it to show the difference between i (a primitive) and inner_level (a reference type).
Here we have a module with one sobriety variable local to it, and two functions made global (by assigning them to properties of window object). Note that these global functions will have access to sobriety variable even after the module which has it defined is finished (in-context).
inception function, when invoked, defines five variables: two scalar (i and j) and three reference (inner_level, level and food), then defines a function and return it.
This function apparently access i and level (the same context), and sobriety (the outer level context) - but not j and food. Hence latter would be collected by GC right after window.inception is complete; the former, though, stay uncollected - because they're referred by the inner functions.
Now the tricky part. While you don't see access for inner_level in this function, it's still accessed - as it's a value of level property of the same-named object. And, when you check the results, you'd see that all three elements have the same level.i value - equal to 2. That's what's understood by "variables that are referenced by in-context variables".

Are the terms "global property" and "global variable" synonyms?

The global object serves as the top-level lexical environment (the top of the scope-chain, if you will). This means that global properties may be accessed via direct references (like variables):
// global code
this.foo = 1; // creating a global property
foo // accessing the global property via a direct reference
This also means that global variables may be accessed via property references:
// global code
var foo = 1; // creating a global variable
this.foo // accessing the global variable via a property reference
INTERPRETATION 1
Now, based on the above information, it would seem that it would be appropriate to use the terms "global variable" an "global property" interchangeably, meaning that both terms represent the exact same set of global bindings.
However, there are two differences between a global variable created using var ,e.g. var foo = 1;, and a global property created through an assignment, e.g. this.foo = 1;:
Global variables are statically scoped, whereas global properties are dynamically added to the global environment:
foo // => undefined
bar // throws ReferenceError
var foo = 1;
this.bar = 1;
So, global variables are bound before program evaluation, whereas global properties are bound during program evaluation, when the assignment is evaluated.
Global variables are non-configurable, i.e. they cannot be deleted (more specifically, their corresponding bindings cannot be removed from the environment subsequently), whereas global properties created through assignment are configurable.
// the names "foo" and "bar" are bound to the global environment
var foo = 1;
this.bar = 1;
// the binding "bar" can be removed from the global environment subsequently
delete this.bar;
// the binding "foo" cannot be removed subsequently
That being said, it should be noted that it is possible to create non-configurable global properties:
Object.defineProperty( this, 'bar', { value: 1 }); // non-configurable by default
INTERPRETATION 2
Now, based on this new information, one could say that only statically scoped global bindings may be referred to as both global properties and global variables, whereas dynamically added global bindings are merely global properties, but not global variables, meaning that the term "global variable" represents a subset of the set represented by the term "global property", as in:
All global variables are global properties
Only statically scoped global properties are global variables
So, which interpretation is correct? Do both terms represent the same set of bindings, or is one a subset of the other?
THE QUESTION
I do understand the term "global property" - a global property is a property of the global object. However, the term "global variable" appears to be ambiguous. Some use it as a synonym for "global property", while others define it to mean a global property which has been defined via a var statement. The intent of my question is to determine which of these two meanings is correct
Well, you already know everything I would have said to differentiate between the edge-cases of variables and properties which are attached to window.
If you wanted to get really, really pedantic, I suppose that you could consider the global scope to be both a functional-scope and a scope in which the window object is extended with properties using the same hidden configuration settings as what is provided within the program (eg: vars can be reassigned but not deleted). So in that sense, as far as functionality is concerned, they are different, and reflect attributes of properties and variables, globally scoped.
And referring to them as such is totally fine.
But the majority of people out there don't even recognize the difference, let alone differentiate between the two terms.
Even the important JS authors out there have referred to setting a global variable accidentally, by omitting var, when really, JS scales the function scopes, and if it makes it to the global scope without hitting that name, it appends a global property with that data, rather than a global variable.
But that really sort of brings us to the crux -- a strong and stable and reliable JS application, living on a modern webpage along with other applications, really shouldn't be too concerned with the differences.
The goal is to use as few global properties and variables as possible, in that case.
Moreover, the danger of variable/property collision is the same, regardless of which it is.
Variables are immune to delete, but what are the chances that any useful program is going to delete a property it's never even set?
So personally, I think it's good to understand the edge-cases, but I also think that while the pedant in me wants to agree that there's a difference, and they are not coterminous, the pragmatist in me shudders to think of a world where people are actively using the global scope to the extent where this makes a large difference to them.
A good explanation can be found here, but I'll shorten it down to answer your question. When you say:
both terms represent the exact same set of global bindings.
...you're almost correct, but not quite. Property assignments like this.foo = 1 are saved into the global object. Variable declarations like var bar = 2 however are saved into the variable object.
When executing under global scope, both the global object and the variable object are represented by the same object--the global object (when you're executing in a browser, this is the window object).
I mention this because your explanation alone is insufficient to explain the behavior of this program:
// "this" refers to the global object. But global object is also acting as the
// variable object! Because of that, the following code works:
var foo = 1;
alert(this.foo); // 1
(function() {
// "this" still refers to the global object! But the *variable* object has
// changed because we're now in the execution context of a function, thus
// the behavior changes:
var bar = 2;
alert(this.foo); // 1
alert(this.bar); // undefined
})();
This doesn't mean that global properties and global variables are identical however. There are three hidden flags on all properties: ReadOnly, DontEnum, and DontDelete.
When using implicit property declarations like this.foo = 1, the DontDelete attribute is set to false. When you use variable declarations like var bar = 2, the DontDelete attribute is set to true, thus representing the difference between them when you use the delete operator.
In response to your rephrased question:
[T]he term "global variable" appears to be ambiguous. Some use it as a
synonym for "global property", while others define it to mean a global
property which has been defined via a var statement. The intent of my
question is to determine which of these two meanings is correct.
The term is not clearly defined, and therefore you are asking for nothing more than an opinion.
In general, the term "global property" is used when you create a variable using the syntax this.foo = 1, and the term "global variable" is used when you create a variable using the syntax var bar = 2. There's nothing more to discuss.
Neither term has a true bearing on what goes on behind the scenes, thus the best you can do is understand what actually goes on behind the scenes, which you have already done.
Further demanding an absolute definition on two arbitrary terms will simply cause you to be an unpopular person.

Different behaviour of delete keyword on global variables

Please consider the following snippet (fiddle here):
​var a;
​a = 1;
console.log(delete a​); // prints 'false'
​b = 1;
console.log(delete b);​ // prints 'true'​​​​
Why does the delete keywords behave differently on the global variables a and b?
From the MDN docs:
The delete operator removes a property from an object.
A global variable (without var) is a property on the global object (typically window), so can be deleted.
A var is not a global variable, but a local variable in the outer scope - not a property of the global object - so delete does not delete it. From those docs:
x = 42; // creates the property x on the global object
var y = 43; // declares a new variable, y
delete x; // returns true (x is a property of the global object and can be deleted)
delete y; // returns false (delete doesn't affect variable names)
MDN says delete returns false only if the property exists and cannot be deleted. It returns true in all other cases. After deleting, try testing the actual values. You'll see that a was not deleted. This is because, as the MDN page says, delete will not affect variable names.
It has no effect on variable or function names.
(i.e., defined with var and not off the global object)
Take a look at the examples on the following page.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/delete
From mozilla docs about var :
The difference is that a declared variable is a non-configurable property of the global object while an undeclared is configurable.
var a; --> This is a declared variable, because you are using var, so it's not configurable.
a = 6; --> This is an undeclared variable, because you are not using var, so it's configurable.
both syntaxes above will end up with a var named a attached as a property of the global object (window typically) and properties has these attributes:
Writable. If false, the value of the property can not be changed.
Configurable. If false, any attempts to delete the property or change its attributes (Writable, Configurable, or Enumerable) will fail.
Enumerable. If true, the property will be iterated over when a user does for (var prop in obj){} (or similar).
that is extracted from ecmascript5 objects and properties , and as you can read, the configurable attribute of the variable in question affects whether the variable can or cannot be deleted.
"var a" means it cannot be accessed from anywhere outside of the current block, thus deleting it WOULD mean UNDECLARE (not same as undefined), thus allowing to write "var a" again in the same block (error).
Allowed usages (MDN):
delete object.property
delete object['property']
delete object[index]
delete property
It's like GOTO and unstructured programming, where you might need to manually clean up resources, it's kind of ~Destructor in C (though not the same). You can delete an object like ~a(); but you cannot "'UNDECLARE' a variable" like "int i".

Difference between creating a global variable, vs one in a constructor function in JavaScript

If I declare a global variable x as:
var x = "I am window.x";
x will be a public property of the window object.
If I call a global function (without using "call", "apply" or attaching it to another object first), the window object will be passed in as the context (the “this” keyword).
It is like it is siting the x property on the current context, which happens to be the window.
If, however, I declare a variable in the same way inside a function, then use that function as a constructor, the property x will not be a public property of the object I just constructed (the current context). I am happy (I know I can do this.x = …), but it just seems like a bit of a contradiction.
Have I misunderstood something (about it being a contradiction / different behaviour)? Would anyone be able to explain what is going on, or is it just something I have to accept?
Hope that my question is clear.
It seems like you've understood it just fine (I pick one small nit with your terminology below). Local variables within constructor functions are just that: Local variables inside constructor functions. They're not part of the instance being initialized by the constructor function at all.
This is all a consequence of how "scope" works in JavaScript. When you call a function, an execution context (EC) is created for that call to the function. The EC has something called the variable context which has a binding object (let's just call it the "variable object," eh?). The variable object holds all of the vars and function arguments and other stuff defined within the function. This variable object is a very real thing and very important to how closures work, but you can't directly access it. Your x in the constructor function is a property of the variable object created for the call to the constructor function.
All scopes have a variable object; the magic is that the variable object for the global scope is the global object, which is window on browsers. (More accurately, window is a property on the variable object that refers back to the variable object, so you can reference it directly. The variable objects in function calls don't have any equivalent property.) So the x you define at global scope is a property of window.
That terminology nit-picking I promised: You've said:
If call a global function, the window object will be passed in as the context (the “this” keyword).
Which is mostly true. E.g., if you call a global function like this:
myGlobalFunction();
...then yes, this will be the global object (window) during the call. But there are lots of other ways you might call that global function where it won't be. For instance, if you assign that "global" function to a property on an object and then call the function via that property, this within the call will be the object the property belongs to:
var obj = {};
obj.foo = myGlobalFunction;
obj.foo(); // `this` is `obj` within the call, not `window`
obj['foo'](); // Exactly the same as above, just different notation
or you might use call or apply features of function objects to set this explicitly:
var obj = {};
myGlobalFunction.call(obj, 1, 2, 3); // Again, `this` will be `obj`
myGlobalFunction.apply(obj, [1, 2, 3]); // Same (`call` and `apply` just vary
// in terms of how you pass arguments
More to explore (disclosure: these are links to my blog, but it doesn't have ads or anything, seems unlikely I'll add them):
Closures are not complicated (explores the scope chain and variable objects and such)
Mythical methods (more about functions and this)
You must remember this (even more about functions and this)
Update: Below you've said:
I just want to check my understanding: In any scope (global or function) there are always 2 objects: a “this” object (what is that called?) and a “variable object”. In the global scope, these 2 objects are the same. In a function’s scope, they are different, and the “variable object” is not accessible. Is that correct?
You're on the right track, and yes, there are always those two things kicking around (usually more; see below). But "scope" and this have nothing to do with each other. This is surprising if you're coming to JavaScript from other languages, but it's true. this in JavaScript (which is sometimes called "context" although that can be misleading) is defined entirely by how a function is called, not where the function is defined. You set this when calling a function in any of several ways (see answer and links above). From a this perspective, there is no difference whatsoever between a function defined a global scope and one defined within another function. Zero. Zilch.
But yes, in JavaScript code (wherever it's defined) there's always this, which may be anything, and a variable object. In fact, there are frequently multiple variable objects, arranged in a chain. This is called the scope chain. When you try to retrieve the value of a free variable (an unqualified symbol, e.g. x rather than obj.x), the interpreter looks in the topmost variable object for a property with that name. If it doesn't find one, it goes to the next link in the chain (the next outer scope) and looks on that variable object. If it doesn't have one, it looks at the next link in the chain, and so on, and so on. And you know what the final link in the chain is, right? Right! The global object (window, on browsers).
Consider this code (assume we start in global scope; live copy):
var alpha = "I'm window.alpha";
var beta = "I'm window.beta";
// These, of course, reference the globals above
display("[global] alpha = " + alpha);
display("[global] beta = " + beta);
function foo(gamma) {
var alpha = "I'm alpha in the variable object for the call to `foo`";
newSection();
// References `alpha` on the variable object for this call to `foo`
display("[foo] alpha = " + alpha);
// References `beta` on `window` (the containing variable object)
display("[foo] beta = " + beta);
// References `gamma` on the variable object for this call to `foo`
display("[foo] gamma = " + gamma);
setTimeout(callback, 200);
function callback() {
var alpha = "I'm alpha in the variable object for the call to `callback`";
newSection();
// References `alpha` on the variable obj for this call to `callback`
display("[callback] alpha = " + alpha);
// References `beta` on `window` (the outermost variable object)
display("[callback] beta = " + beta);
// References `gamma` on the containing variable object (the call to `foo` that created `callback`)
display("[callback] gamma = " + gamma);
}
}
foo("I'm gamma1, passed as an argument to foo");
foo("I'm gamma2, passed as an argument to foo");
function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}
function newSection() {
document.body.appendChild(document.createElement('hr'));
}
The output is this:
[global] alpha = I'm window.alpha
[global] beta = I'm window.beta
--------------------------------------------------------------------------------
[foo] alpha = I'm alpha in the variable object for the call to `foo`
[foo] beta = I'm window.beta
[foo] gamma = I'm gamma1, passed as an argument to foo
--------------------------------------------------------------------------------
[foo] alpha = I'm alpha in the variable object for the call to `foo`
[foo] beta = I'm window.beta
[foo] gamma = I'm gamma2, passed as an argument to foo
--------------------------------------------------------------------------------
[callback] alpha = I'm alpha in the variable object for the call to `callback`
[callback] beta = I'm window.beta
[callback] gamma = I'm gamma1, passed as an argument to foo
--------------------------------------------------------------------------------
[callback] alpha = I'm alpha in the variable object for the call to `callback`
[callback] beta = I'm window.beta
[callback] gamma = I'm gamma2, passed as an argument to foo
You can see the scope chain at work there. During a call to callback, the chain is (top to bottom):
The variable object for that call to callback
The variable object for the call to foo that created callback
The global object
Note how the variable object for the call to foo lives on past the end of the foo function (foo returns before callback gets called by setTimeout). That's how closures work. When a function is created (note that a new callback function object is created each time we call foo), it gets an enduring reference to the variable object at the top of the scope chain as of that moment (the whole thing, not just the bits we see it reference). So for a brief moment while we're waiting our two setTimeout calls to happen, we have two variable objects for calls to foo in memory. Note also that arguments to functions behave exactly like vars. Here's the runtime of the above broken down:
The interpreter creates the global scope.
It creates the global object and populates it with its default set of properties (window, Date, String, and all the other "global" symbols you're used to having).
It creates properties on the global object for all var statements at global scope; initially they have the value undefined. So in our case, alpha and beta.
It creates properties on the global object for all function declarations at global scope; initially they have the value undefined. So in our case, foo and my utility functions display and newSection.
It processes each function declaration at global scope (in order, top to bottom):
Creates the function object
Assigns it a reference to the current variable object (the global object in this case)
Assigns the function object to its property on the variable object (again, the global object in this case)
The interpreter begins executing the step-by-step code, at the top.
The first line it reaches is var alpha = "I'm window.alpha";. It's already done the var aspect of this, of course, and so it processes this as a straight assignment.
Same for var beta = ....
It calls display twice (details omitted).
The foo function declaration has already been processed and isn't part of step-by-step code execution at all, so the next line the interpreter reaches is is foo("I'm gamma1, passed as an argument to foo");.
It creates an execution context for the call to foo.
It creates a variable object for this execution context, which for convenience I'll call foo#varobj1.
It assigns foo#varobj1 a copy of foo's reference to the variable object where foo was created (the global object in this case); this is its link to the "scope chain."
The interpreter creates properties on foo#varobj1 for all named function arguments, vars, and function declarations inside foo. So in our case, that's gamma (the argument), alpha (the var), and callback (the declared function). Initially they have the value undefined. (A few other default properties are created here that I won't go into.)
It assigns the properties for the function arguments the values passed to the function.
It processes each function declaration in foo (in order, beginning to end). In our case, that's callback:
Creates the function object
Assigns that function object a reference to the current variable object (foo#varobj1)
Assigns the function object to its property on foo#varobj1
The interpreter begins step-by-step execution of the foo code
It processes the assignment from the var alpha = ... line, giving foo#varobj1.alpha its value.
It looks up the free variable newSection and calls the function (details omitted, we'll go into detail in a moment).
It looks up the free variable alpha:
First it looks on foo#varobj1. Since foo#varobj1 has a property with that name, it uses the value of that property.
It looks up display and calls it (details omitted).
It looks up the free variable beta:
First it looks on foo#varobj1, but foo#varobj1 doesn't have a property with that name
It looks up the next link in the scope chain by querying foo#varobj1 for its reference to the next link
It looks on that next link (which happens to be the global object in this case), finds a property by that name, and uses its value
It calls display
It looks up gamma and calls display. This is exactly the same as for alpha above.
It looks up the free variable callback, finding it on foo#varobj1
It looks up the free variable setTimeout, finding it on the global object
It calls setTimeout, passing in the arguments (details omitted)
It returns out of foo. At this point, if nothing had a reference to foo#varobj1, that object could be reclaimed. But since the browser's timer stuff has a reference to the callback function object, and the callback function object has a reference to foo#varobj1, foo#varobj1 lives on until/unless nothing refers to it anymore. This is the key to closures.
Wash/rinse/repeat for the second call to foo, which creates foo#varobj2 and another copy of callback, assigning that second callback a reference to foo#varobj2, and ultimately passing that second callback to setTimeout and returning.
The interpreter runs out of step-by-step code to execute and goes into its event loop, waiting for something to happen
About 200 milliseconds go by
The browser's timer stuff tells the interpreter it needs to call the first callback function we created in foo
The interpreter creates an execution context and associated variable object (callback#varobj1) for the call; it assigns callback#varobj1 a copy of the variable object reference stored on the callback function object (which is, of course, foo#varobj1) so as to establish the scope chain.
It creates a property, alpha, on callback#varobj1
It starts step-by-step execution of callback's code
You know what happens next. It looks up various symbols and calls various functions:
Looks up newSection, which it doesn't find on callback#varobj1 and so looks at the next link, foo#varobj1. Not finding it there, it looks at the next link, which is the global object, and finds it.
Looks up alpha, which it finds on the topmost variable object, callback#varobj1
Looks up beta, which it doesn't find until it gets down to the global object
Looks up gamma, which it finds only one link down the scope chain on foo#varobj1
The interpreter returns from the call to callback
Almost certainly, there in its event queue there's a message from the browser waiting for it, telling it to call the second callback function, which we created in our second call to foo.
So it does it all again. This time, the variable object for the call to callback gets a reference to foo#varobj2 because that's what's stored on this particular callback function object. So (amongst other things) it sees the gamma argument we passed to the second call, rather than the first one.
Since the browser has now released its references to the two callback function objects, they and the objects they refer to (including foo#varobj1, foo#varobj2, and anything their properties point to, like gamma's strings) are all eligible for garbage collection.
Whew That was fun, eh?
One final point about the above: Note how JavaScript scope is determined entirely by the nesting of the functions in the source code; this is called "lexical scoping." E.g., the call stack doesn't matter for variable resolution (except in terms of when functions get created, because they get a reference to the variable object in scope when they were created), just the nesting in the source code. Consider (live copy):
var alpha = "I'm window.alpha";
function foo() {
var alpha = "I'm alpha in the variable object for the call to `foo`";
bar();
}
function bar() {
display("alpha = " + alpha);
}
foo();
What ends up getting output for alpha? Right! "I'm window.alpha". The alpha we define in foo has no effect whatsoever on bar, even though we called bar from foo. Let's quickly walk through:
Set up global execution context etc. etc.
Create properties for the vars and declared functions.
Assign alpha its value.
Create the foo function object, give it a reference to the current variable object (which is the global object), put it on the foo property.
Create the bar function object, give it a reference to the current variable object (which is the global object), put it on the bar property.
Call foo by creating an execution context and variable object. The variable object, foo#varobj1, gets a copy of foo's reference to its parent variable object, which is of course the global object.
Start step-by-step execution of foo's code.
Look up the free variable bar, which it finds on the global object.
Create an execution context for the call to bar and its associated variable object bar#varobj1. Assign bar#varobj1 a copy of bar's reference to its parent variable object, which is of course the global object.
Start step-by-step execution of bar's code.
Look up the free variable alpha:
First it looks on bar#varobj1, but there's no property with that name there
So it looks at the next link, which is the link it got from bar, which is the global object. So it finds the global alpha
Note how foo#varobj1 isn't linked at all to bar's variable object. And that's good, because we'd all go nuts if what was in scope was defined by how and from where a function was called. :-) Once you understand that it's linked to function creation, which is dictated by the nesting of the source code, it gets a lot easier to understand.
And that's why what's in scope for bar is determined entirely by where bar is in the source code, not how it got called at runtime.
It's not surprising that initially you were wondering about the relationship between this and variable resolution, because the global object (window) serves two unrelated purposes in JavaScript: 1. It's the default this value if a function isn't called in a way that sets a different one (and at global scope), and 2. It's the global variable object. These are unrelated aspects of what the interpreter uses with the global object for, which can be confusing, because when this === window, it seems like variable resolution relates in some way to this, but it doesn't. As soon as you start using something else for this, this and variable resolution are completely disconnected from one another.
Your understanding of properties and constructors is fine; the concepts you're missing are 'scopes' and 'closures'. This is where var comes into play.
Try reading Robert Nyman's explanation
You have some examples in this fiddle :
var x = 42;
function alertXs() {
this.x = 'not 42'; // this = window
var x = '42 not'; // local x
alert('window.x = ' + window.x); // 'not 42'
alert('this.x = ' + this.x); // 'not 42'
alert('x = ' + x); // '42 not'
}
alertXs();
http://jsfiddle.net/Christophe/Pgk73/
Sometimes, creating tiny fiddles helps to understand...
But you are aware with local and public variable as you explain that very well...

Categories

Resources