OO Javascript : Definitive explanation of variable scope - javascript

Can someone provide an explanation of variable scope in JS as it applies to objects, functions and closures?

Global variables
Every variable in Javascript is a named attribute of an object. For example:-
var x = 1;
x is added to the global object. The global object is provided by the script context and may already have a set of attributes. For example in a browser the global object is window. An equivalent to the above line in a browser would be:-
window.x = 1;
Local variables
Now what if we change this to:-
function fn()
{
var x = 1;
}
When fn is called a new object is created called the execution context also referred to as the scope (I use these terms interchangeably). x is added as an attribute to this scope object. Hence each call to fn will get its own instance of a scope object and therefore its own instance of the x attribute attached to that scope object.
Closure
Now lets take this further:-
function fnSequence()
{
var x = 1;
return function() { return x++; }
}
var fn1 = fnSequence();
var fn2 = fnSequence();
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn2())
Note: Replace WScript.Echo with whatever writes to stdout in your context.
The sequence you should get is :-
1 1 2 2 3 4 3 4
So what has happened here? We have fnSequence which initialises a variable x to 1 and returns an anonymous function which will return the value of x and then increment it.
When this function is first executed a scope object is created and an attribute x is added to that scope object with the value of 1. Also created in the same execution object is an anonymous function. Each function object will have a scope attribute which points to the execution context in which it is created. This creates what is know as a scope chain which we will come to later. A reference to this function is returned by fnSequence and stored in fn1.
Note that fn1 is now pointing at the anonymous function and that the anonymous function has a scope attribute pointing at a scope object that still has an x attribute attached. This is known as closure where the contents of an execution context is still reachable after the function it was created for has completed execution.
Now this same sequence happens when assigning to fn2. fn2 will be pointing at a different anonymous function that was created in a different execution context that was create when fnSequence was called this second time.
Scope Chain
What happens when the function held by fn1 is executed the first time? A new execution context is created for the execution of the anonymous function. A return value is to be found from the identifier x. The function's scope object is inspected for an x attribute but none is found. This is where the scope chain comes in. Having failed to find x in the current execution context JavaScript takes the object held by the function's scope attribute and looks for x there. It finds it since the functions scope was created inside an execution of fnSequence, retrieves its value and increments it. Hence 1 is output and the x in this scope is incremented to 2.
Now when fn2 is executed it is ultimately attached to a different execution context whose x attribute is still 1. Hence executing fn2 also results in 1.
As you can see fn1 and fn2 each generate their own independent sequence of numbers.

Variables not declared with var are global in scope.
Functions introduce a scope, but note that if blocks and other blocks do not introduce a scope.
I could also see much information about this by Googling Javascript scope. That's really what I would recommend.
http://www.digital-web.com/articles/scope_in_javascript/

Functions introduce a scope. You can declare functions inside other functions, thereby creating a nested scope. The inner scope can access the outer scope, but the outer can not access the inner scope.
Variables are bound to a scope, using the var keyword. All variables are implicitly bound to the top-level scope. So if you omit the var keyword, you are implicitly referring to a variable bound to the top level. In a browser, the top level is the window object. Note that window is it self a variable, so window == window.window

Related

Does top level functions makes closure in JavaScript?

I am learning closure and have basic doubt.
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
Here when we are returning function it has closure with outer scope. so it has a closure with count.
var x = 1;
function func() {
console.log(x); // does func has closure with x ??
}
func();
So my question is , only nested function makes closure ??
or top level func has also closure with x ??
Closures in JavaScript are implemented using the [[OuterEnv]] internal field of the [[EnvironmentRecord]] internal field of function declarations. The [[OuterEnv]] value is then copied to the execution context created any time a function is called. This value is then used to create the scope chain, enabling the closure behavior.
Functions declared in the global context are no different in this regard and maintain a link to their surrounding environment, the Global Environment Record.
In the global context, variables declared using var and function declarations behave subtly differently to those declared inside other functions, in that they end up as properties on the global object, but this is an implementation detail.
For the sake of conversation, lets say that every closure creates a "scope" where variables are defined - everything within the closure/scope can access variables, anything outside cannot. With that said, there are two different types of implied closures you should be aware of.
This is not an exhastive description of how closures work, but more of description of the basic practical concepts as they relate to this question. There is much more going on with how call stacks are created, lexical scoping, "global" scope within NodeJS, iframes, sandboxing, var vs const/let, block vs function scopes, and other concepts which I will leave to the reader to discover on their own.
The browser/window/global scope
In the browser, you have the top-level scope (basically window, often referred to as the "global" scope). This kind of acts as a closure in that all "non-enclosed" variables are defined as part of the window scope and are available to most other code running on that page. For example, if you include the following script in the browser, x is part of the global/window scope, whereas y and z are enclosed inside their own nested scopes.
// basic-script.js
// x becomes part of the global/window scope
const x = 10;
(() => {
// y is enclosed in a separate, nested closure
const y = 20;
// x is available in this nested scope/closure
console.log('The sum of x and y is', x + y);
function foo() {
// z is enclosed in a separate, nested closure
const z = 5;
// x and y are both available in this nested scope/closure
console.log('The sum of x y and z is', x + y + z);
}
foo();
// z is not available to the parent scope
console.log(z); //-> undefined
})();
// y is not available to the parent scope
console.log(y); //-> undefined
<script src="basic-script.js"></script>
<script>
// this works because x is not enclosed
console.log('The value of x is', x);
// y and z are not available as they are inside a separate closure
console.log(y, z); //-> undefined, undefined
</script>
JavaScript modules
When you write JavaScript which is imported or required by other modules, every module is automatically wrapped in its own closure. For example, if you were to import/require the above basic-script.js into another JavaScript file, the above would be automatically enclosed like this:
(function() {
var x = 10;
// ... other code removed for brevity
})();
There is some other magic going on for exposing exports and so forth, but that's beyond the scope of this answer (pun intended). If JS modules were not wrapped in their own closure, then you would have a mess of naming collisions and reference issues, as well as a security nightmare.
So to answer your question, yes - your second example shares a closure with "x" - the closure is implicitly created depending on your environment.
Don't know, if you are still searching for the answer or not.
What is you meant by top level, I think you are talking about the global scope. To understand closure one should understand scope better.
And No, Closure in not work in global scope. The main reason of closure is to create a function that return a function with specific variables/calculations with it so that you can reuse that value again. I have a detailed blog in scope, closure and lexical environment. You can check it out https://shimulhsn.hashnode.dev/lexical-environment-and-scope-chain
A practical use of closures is creating a "scope" of protection around variables and functions declared within that function from outside interference. The top scope is "global", accessed using the window variable (an object). Everything, regardless what scope it was declared in, has access to it.
A function declared in global scope creates its own scope that no expression in the global scope and other "sub-global" scopes has access to. Functions declared in the global scope or declared inside other functions create their own scope, that even its immediate parent scope doesn't have access to.
Any variable declared—var, let, const—inside a function block is accessible in that function scope and any sub-scope created within that function scope—i.e., nothing outside that function scope can access it, (except a mechanism the function creating the scope may provide).
The second example in the question, where x is declared in the global scope, means everything has access to x. If x is later changed it is changed in all scopes. x is wide-open to interference anywhere in the code.
var x = 1; <-- declared outside func()
function func() {
// ...etc., etc., etc.
In the first example:
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
...makeCounter() creates a scope that includes count and an anonymous function, and that has access to them. Sub-scopes within this scope also have access to them. However, any expression in the global scope or other sub-global scopes do not have access to them.
Regarding the description that closures give access to an outer function's scope from an inner function—that scope access travels "up", accessing every parent scope, all the way to global scope, regardless how far "down" the "scope-chain" it goes. For example:
const can_i_reach_global = 'yes';
topLevel();
function topLevel () {
console.log('topLevel func, can_i_reach_global:', can_i_reach_global);
oneDeep();
function oneDeep () {
console.log('oneDeep func, can_i_reach_global:', can_i_reach_global);
twoDeep();
function twoDeep () {
console.log('twoDeep func, can_i_reach_global:', can_i_reach_global)
}
}
}
So, as far as practical definitions go, simply stating function closure "...gives you access to an outer function's scope from an inner function..." doesn't describe the usefulness of this programming construct.

Values of variables in scope when using closure in JavaScript

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/

Javascript - understanding the scope chain's reference priority

I would like to better understand the scope chain the hopefully closure better and so the following code:
function greet(whattosay){
return function(name) {
whattosay = "not hi"; //change the hi message
console.log(whattosay + ' ' + name);
function insideAnon() {
console.log(whattosay);
}
}
}
var sayHi = greet('Hi'); //get in return the anon function
sayHi("John"); //print not hi John on the console
I have recently learned that every "variable environment" is actually an array or an object with properties, and so each function has a reference to it's parent's function variable environment object/array. But my question is, what exactly is the scope chain?(I know that it is supposedly going "down" up until the global level), My current perception (Not sure) is that each child has it's parent and grandparent (and so on) variable environment references inside of it, and so it first check it's parent's variable environment object, if a variable is not there it looks at it's grandparent's reference and so on. Or is it more like - Check the parent variable environment object reference, if not there that parent checks his parent's reference and so on. I HOPE i was very clear at what I was trying to say - How it really goes down the "chain".
You can get references about scope chains from this question:
Scope Chain in Javascript
Each function creates a scope object that contains the arguments for that function and the local variables defined in that function.
Since Javascript uses lexical scoping, that means that a given piece of code can access variables defined within the current function or within any parent function. Javascript makes this work by maintaining a chain of scope objects so each scope has a reference to its parent scope.
When a given piece of code accesses a variable like:
foo = 1;
Javascript, looks in the current scope object to see if something named foo exists there. If so, that variable is used. If not, it gets the reference to the parent scope, checks that scope for something named foo and continues this process up the parent chain until it gets to the global scope and thus can go no further.
So, in this example:
function one() {
var foo = 2;
function two() {
var fee = 3;
function three() {
foo = 1;
}
three();
}
two();
}
one();
The function one() will execute and define foo and two in its scope. It will then call two() which will execute and define fee and three in its scope. It will then call three() which will execute and attempt to change the value of foo. It will first look in the scope object belonging to three, but it will not find anything named foo there so it will go to the parent scope of three which will be the two scope object. It will not find a variable named foo in that scope object so it will go to the parent object of two which will be the scope object of one. There it will find a variable named foo so it will change the value of that variable.
On thing that is different about Javascript scope objects compared to something like a C++ stack frame is that they can continue to live after the function that created them has finished executing. This is a very common structure in Javascript and is often referred to as a closure. Here's a simple example of that:
function initializeCntr() {
var cntr = 0;
document.getElementById("test").addEventListener("click", function(e) {
++cntr;
document.getElementById("clickCnt").innerHTML = cntr;
});
}
initializeCntr();
In this short code example, there are three scopes present, the global scope (that contains the initializeCntr symbol), the initializeCntr scope that contains the cntr variable and the scope that belongs to the anonymous function that is set as the event handler.
When you call initializeCntr(), it creates a function scope object that contains the variable cntr. It then runs the addEventListener() method and passes a reference to the inline anonymous event handler for addEventListener(). The initializeCntr() method then finishes execution. But, because the inline anonymous function passed as the event handler contains a reference to the cntr variable in the initializeCntr scope object, that scope object is NOT garbage collected even though initializeCntr() has finished executing. Instead, it is kept alive because of the lasting reference to the cntr variable in it. When that click event handler is then called sometime in the future, it can use that cntr variable. In fact, the initalizeCntr scope will be kept alive as long as the event handler is active. If the event handler is removed or the DOM object it is attached to is removed, then and only then would the initializeCntr scope object be eligible for garbage collection and eventually get freed.
Some JS implementations are smart enough to not necessarily retain the entire scope object and everything in it, but instead to only retain the elements of the scope object that are specifically referenced in child scopes that are still active. So, if there were other variables next to cntr that were not used in the event handler, those other variables could be freed.
FYI, this longer lasting scope is called a closure. Closures are very useful concepts in Javascript and something not available in a language like C++ (because they rely on garbage collection).

Why this keyword is necessary for accessing own object in Javascript

var simpleObject={n:70};
simpleObject.testMethod=function(){
console.log(n);
}
Why do i need to write this.n inside console.log to show the output 70.
The 'this' keyword refers to the object itself, the property n is a member of the object, and thus it must be accessed via that namespace 'this.n'.
However if the variable was declared inside the same function (i.e. testMethod), via 'var n = 0', then within that same closure/scope you could access the variable with just 'n' (without 'this').
But the property n is outside the 'testMethod' function scope, and thus must be accessed via the proper namespace - hence 'this.n'.
JavaScript is a dynamic language. This essentially means that it uses dynamic name resolving and function objects. Thus you can take function from one object and assign it to another. Consider this:
var simpleObject={n:70};
simpleObject.testMethod=function(){console.log(this.n);}
var simpleObject2={foo:42};
simpleObject2.testMethod = simpleObject1.testMethod;
simpleObject.testMethod();
simpleObject2.testMethod();
Both objects here are using the same function, first call will print 70. But second will print undefined.
this is not necessary, it's just a way to do it. Another trivial way would be simpleObject.n.
However, it seems that you want the identifier n to be avaluated to a reference to simpleObject.n.
Identifiers are resolved using property lookups to the binding object of the environment record of the LexicalEnvironment of the running execution context. Initially, it is [[Scope]]:
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:
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.
To achieve what you want, you need to set the running execution context's LexicalEnvironment to NewObjectEnvironment(this, oldEnvironment).
You can achieve that using the width statement:
The with statement adds an object environment record for a
computed object to the lexical environment of the current
execution context. It then executes a statement using this augmented
lexical environment. Finally, it restores the original lexical
environment.
var simpleObject = {n: 70};
simpleObject.testMethod = function(){
with(this) {
console.log(n);
}
};
simpleObject.testMethod(); // 70
However, note that the use of with is discouraged, and won't work in strict mode.
Another way is taking advantage of the fact that the scope in event handler content attributes is the global one shadowed by the document, the form owner, and the element:
Let Scope be the result of NewObjectEnvironment(document, the global environment).
If form owner is not null, let Scope be the result of NewObjectEnvironment(form owner, Scope).
If element is not null, let Scope be the result of NewObjectEnvironment(element, Scope).
Then, you can let your object be an HTML element, and let your method be an internal raw uncompiled handler:
var el = document.createElement('div');
el.n = 70;
el.setAttribute('onclick', 'console.log(n)');
el.click(); // 70

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