2013-12-19 176 views
2

据我所知,不带“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) 
  1. 当我们调用var o = Test(),到底发生了什么吗? Test()在什么情况下执行。由于new关键字缺失,我相信,this里面的Test3()会参考窗口? “o”指的是什么?它只是一个在全局上下文中声明的变量吗?

  2. 如果上述属实,那么o和o2如何能够维护Test3局部变量“a”的单独副本。我知道我们在这里已经关闭了,但是接下来怎么回事,“o2”和“window”共享同一个变量“a”,但不是“o”当我做var o = Test3时()然后做alert(o.testRef()===窗口),它说错误。所以执行后:

    var o = Test3(); 
    var o2 = Test3(); 
    

似乎有从Test3()属性的3份。一个关于“o”,另一个关于“o2”,另一个关于全球范围。

但是怎么能有“o”和“o2” - 我不是用“new”关键字调用Test3(),所以这应该只涉及全局上下文?

+1

帮你一个忙,把''use strict';'加到脚本的顶部。 – Pointy

+0

在JSBin中工作。我认为它默认启用了“严格”​​。试图严格使用;但JSBin正在抱怨这一行。什么会有“严格”做? –

+0

@TahaAhmad你有没有把''严格使用';'或'严格使用'?你应该使用带引号的那个... – dg123

回答

1

每次调用Test3时,incnoInctestRef功能被重新分配给window具有不同a(这是在函数的顶部初始化为0。)

windowo2共享相同的a因为当o2获得返回值而不是o1时,函数被重新分配到window。从REPL的NodeJS

例子(注意的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 

的功能被重新分配给全局对象,与0a,而o会保持以前a

+0

精美的解释! –

+0

一个后续问题: 在我的代码中,在var o = Test3()之前,如果我做了var o4 = new Test3(),代码停止工作并给出错误 - “ReferenceError:inc未定义”。这里发生了什么? –

+2

@TahaAhmad:由于'this'不再指'window','this.inc = function(){...}'不*创建全局变量和'return {inc:inc,.. 。}抛出一个错误,因为inc没有在任何范围内定义。 –

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? 

所以基本上你要覆盖绑定到不同的aincnoinc定义。

如果不是var a = 0你有this.a = this.a || 0你会绑定到相同a

+0

这不是我的代码所做的: o.inc(),o2 .inc()维护自己的“a”副本。然而o2似乎在全球范围内共享“a” –

+0

这并不准确。 'o2'不共享'a'(它是_private_),只是'this.inc === o2.inc'。如果你做了'o3 = Test3()',现在'o3'将成为'o2'之前的东西,'o2'将会变成'o'。 – Halcyon

+0

非常好。但是,window.inc()来自哪里,或者o.inc()来自哪里?不是Test3()在全局上下文(窗口)中执行,因此inc()只应在窗口上可用。如果是,导致“o”得到inc()(和其他属性)的原因是什么? –