2013-12-19 171 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()(和其他屬性)的原因是什麼? –