Reputation: 559
I understand that functions called without the "new" keyword spit out all their properties on to the global context. But I am seeing some curious behavior, with this piece of Javascript code:
function Test3() {
var a=0;
this.inc = function() {
return ++a;
};
this.noInc = function() {
return a;
};
this.testRef = function() {
return this;
};
return {
inc: inc,
testRef: testRef,
noInc: noInc
};
}
var o = Test3(); // Put func properties on global context
var o2 = Test3(); // Put func properties on global context (replacing properties above??)
// Both "o" and "o2" maintain their own copy of "a" (closure)
alert("o: " + o.inc());
alert("o: " + o.inc());
alert("o: " + o.inc()); // Will output 3 (as expected)
alert(noInc()); // Output: 1 (This seems to not be affected by o.inc() calls - expected)
// However...
alert("o2: " + o2.inc());
alert("o2: " + o2.inc());
alert("o2: " + o2.inc());
alert("o2: " + o2.inc()); // Will output 4 (as expected)
alert(noInc()); // Will output 4 (seems to share with o2), but why?
alert(o === window); // false
alert(o.testRef() === o); // true (I thought testRef() would be on global context?)
alert(o.testRef() === window); // false (^^)
alert(o2 === window); // false
alert(o2.testRef() === o2); // true (I thought testRef() would be on global context?)
alert(o2.testRef() === window); // false (^^)
alert(testRef() === window); // true (How come this is here? Look at comments above)
When we call var o = Test()
, what exactly happens here? What context does Test()
execute in. Since the new
keyword is missing, I believe, this
inside Test3()
would refer to window? What does "o" refer to? Is it simply a variable declared on the global context?
If above is true, then how are o and o2 able to maintain separate copies of Test3's local variable "a". I understand that we have closure in action here, but then how come, "o2" and "window" share the same copy of the variable "a", but NOT "o"
When I do var o = Test3() and then do alert(o.testRef() === window), it says false. So after executing:
var o = Test3();
var o2 = Test3();
There seems to be 3 copies of the properties from Test3()
. One on "o", another one on "o2" and one on the global context.
But how can there be any on "o" and "o2" - I am not calling Test3()
with the "new" keyword, so this should only refer to global context?
Upvotes: 2
Views: 536
Reputation: 6563
Every time you call Test3
, the inc
, noInc
and testRef
functions are reassigned to window
with a different a
(which is initialized to 0
at the top of the function.)
window
and o2
share the same a
because the functions were reassigned to window
when o2
got the return value and not o1
.
Example from NodeJS REPL (note in NodeJS, the global object is referenced by global
instead of window
, but otherwise there shouldn't be any difference):
> function Test3() {
... var a=0;
...
... this.inc = function() {
... return ++a;
... };
...
... this.noInc = function() {
... return a;
... };
...
... this.testRef = function() {
... return this;
... };
...
... return {
... inc: inc,
... testRef: testRef,
... noInc: noInc
... };
... }
undefined
> var o = Test3();
undefined
> o.inc()
1
> o.inc()
2
> o.inc()
3
> noInc()
3
Because Test3
was only called once and set to o1
, both the global scope and o1
share an a
. Now watch as I call Test3
again:
> Test3()
{ inc: [Function],
testRef: [Function],
noInc: [Function] }
> noInc()
0
> o.noInc()
3
The functions are reassigned to the global object, with an a
of 0
, while o
keeps the previous a
.
Upvotes: 1
Reputation: 57721
Your code can be reduced to:
var inc, noinc, a = 0, a2 = 0;
inc = function () {
a += 1;
}
noinc = function () {
return a;
}
inc();
inc();
inc();
noinc(); // 3
inc = function () {
a2 += 1;
}
noinc = function () {
return a2;
}
// now inc and noinc are bound to a2
noinc(); // 0, yours gives 1?
So basically you're overriding the definition of inc
and noinc
bound to a different a
.
If instead of var a = 0
you had this.a = this.a || 0
you would bind to the same a
.
Upvotes: 1