我知道没有“new”关键字调用的函数会将所有属性都吐出到全局上下文中。但我看到一些奇怪的行为,使用这段Javascript代码:
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)
当我们致电var o = Test()
时,这里到底发生了什么? Test()
执行什么上下文。由于缺少new
关键字,我相信,this
内的Test3()
会引用窗口? “o”是指什么?它只是在全局上下文中声明的变量吗?
如果以上是真的,那么o和o2如何能够维护Test3的局部变量“a”的单独副本。我知道我们在这里已经关闭了,但是后来如何,“o2”和“window”共享变量“a”的相同副本,但不是“o”
当我执行var o = Test3()然后执行alert(o.testRef()=== window)时,它会显示false。所以在执行之后:
var o = Test3();
var o2 = Test3();
Test3()
似乎有3个属性副本。一个在“o”上,另一个在“o2”上,另一个在全球背景下。
但是怎么可能有“o”和“o2” - 我没有用“new”关键字调用Test3()
,所以这只应该引用全局上下文?
答案 0 :(得分:1)
您的代码可以缩减为:
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?
所以基本上你要覆盖与inc
绑定的noinc
和a
的定义。
如果您var a = 0
代替this.a = this.a || 0
,则会绑定到相同的 a
。
答案 1 :(得分:1)
每次拨打Test3
时,inc
,noInc
和testRef
功能都会重新分配给window
,其中a
({在函数顶部初始化为0
。)
window
和o2
共享相同的a
,因为当window
获得返回值而非o2
时,函数已重新分配给o1
。
来自NodeJS REPL的示例(注意在NodeJS中,全局对象由global
而不是window
引用,但是否则应该没有任何区别):
> 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
由于Test3
仅被调用一次并设置为o1
,因此全局范围和o1
共享a
。现在看我再次致电Test3
:
> Test3()
{ inc: [Function],
testRef: [Function],
noInc: [Function] }
> noInc()
0
> o.noInc()
3
将函数重新分配给全局对象,a
为0
,而o
保留之前的a
。