2010-01-20 22 views
1

我今天一些審查,當我遇到以下約定:關於這個JavaScript的背景是怎麼回事?

TestParam(1); 

function TestParam(p){ 
    var p = p + 1; 
    alert(p); // alerts '2' 
} 

現在,很明顯,開發商不是故意要在函數內delcare「P」,而不是也許意味着:

p = p + 1; 

但代碼仍然工作,即驚動了值爲「2」。所以它讓我思考。在以下情況下會發生什麼情況:

var a = 1; 
TestParam(a); 
alert(a); // alerts "1" 

function TestParam(p){ 
    var p = p + 1; 
    alert(p); // alerts '2' 
} 

再次提醒是我懷疑的(如上面評論中的暗示)。於是我很好奇會發生什麼,如果我用了一個對象:

var a = { b: 1 }; 
TestParam(a); 
alert(a.b); //alerts 1 

function TestParam(p) { 
    var p = {b:p.b + 1}; 
    alert(p.b); //alerts 2 
} 

所以,在這種情況下,JavaScript有「記住」變量a,即使它被傳遞給TestParam爲p不過,p被重新宣佈。

現在,如果我已經完成了函數內以下,那麼這兩個警報會一直「2」

p.b++; 
    //var p = {b:p.b + 1}; 

即它會修改原始對象的成員b。我明白了。它以前的場景讓我感到困惑!

我意識到這是一個相當假設的問題,它不太可能帶來很多現實世界的用處,但它仍然讓我非常好奇,至於背景中發生了什麼,JavaScript究竟是如何確定範圍並引用它們變量。

有什麼想法?

+0

您確定您對提示(p.a)的最後一個示例是正確的嗎?試圖分析這個,給了我一個想法,傳遞給TesParam的p對象在其中沒有「a」成員。 TestParam內部的警報會給你undefined! – nemisj

+0

對不起 - 錯字 - 與單個字母混淆。也許我應該使用有意義的名稱:-)更正 –

回答

5

變量的作用域JavaScript中的封閉功能。你可以隨意多次聲明它們。

的對象綁變量;許多變量可以引用同一個對象。 (這有時被稱爲走樣)。這是正在發生的事情在你的最後一個例子。 JavaScript根本沒有「記住」變量a;相反,pa指向同一個對象,所以當它通過p改變,您可以通過a看到這些變化。

這裏有一個例子可能更有意義給你。有時一個人有不止一個身份。

var Clark = new Person; 
var Superman = Clark; // Maybe not everybody needs to know these two are 
         // the same person, but they are. 
Clark.eyes = "brown"; 
alert(Superman.eyes); // should be brown, right? 

知道你正在使用的語言的規則有巨大的「真實世界的效用」。不理解這兩條規則是很多混淆和錯誤的根源。

+0

謝謝。我實際上承認了上面的最後一種情況。它是對象重新宣佈我正在努力的倒數第二個案例。 –

+0

啊!在這種情況下,'p = p + 1'實際上改變*變量p *來引用一個不同的數字。分配給'p'後,它不再指向與'a'相同的值。 –

+0

對了你。因此,「一」是指「一個」和「P」是指「A」,直到我重新分配,在這種情況下,「A」還是指「一個」,但「P」指的是不同的東西完全。它就像打破了鏈接!輝煌。感謝:-) –

1

當參數是一個數字或字符串時,Javascript通常會通過引用將所有參數傳遞給函數,但除外。 Javascript通過數字和字符串值這就是爲什麼你的第一個例子工作的方式。

+1

小修正:ARGS不是引用,而是「分享」通行證。這與「參照」非常相似,但不完全相同。在函數內部,我們接收傳入對象的引用_copy_。因此,我們可以通過'param.prop =「foo''改變外在的對象,但如果我們做這樣的事'PARAM =新的對象()'它不會傷害外部對象的。 – NilColor

+0

權之間「按值傳遞」和「按引用傳遞」已成爲絕望渾「引用」一詞老的區別已經意味着完全不同的東西。早在一天,「按引用傳遞」的意思傳遞*給一個變量*或其他存儲位置,這東西只有C++和C#還有事,而不是默認的參考。 –

1

我相信你的代碼中存在拼寫錯誤。我想你的意思是:

function TestParam(p) { 
    var p = {b:p.b + 1}; // p.b, not p.a (p.a == undefined) 
    alert(p.b); 
} 

在您的例子:

var a = { b: 1 }; // "a" is defined in the global scope 
TestParam(a); 
alert(a.b); // alerts 1 

function TestParam(p) { 
    var p = {b:p.a + 1}; // "p" is defined in TestParam()'s scope 
    /* But not until after the expression on the right side of the assignment 
     has completed--that's why you can use p.a 
    alert(p.a); //alerts 2 
} 

起初,「P」作爲全局變量「a」的參考過去了,但後來重新定義它在第一線。因此,例如:

var a = { b: 1 }; 
alert(a.b); // Alerts 1 
TestParam(a); 
alert(a.b); // Alerts 2 
TestParam(a); 
alert(a.b); // Alerts 3 

function TestParam(p) { 
    p.b++; 
} 
+0

是的,發現,可能在你打字的過程中。謝謝你的幫助 :-) –