2010-11-09 73 views
4

我一直在使用JavaScript關閉,使它們本地的返回功能,以保護變量,如:的Javascript關閉,保持外對象

closure = function() { 
    var secretVar = 'Secret'; 

    return { 
     "msg" : function() { 
      console.log(secretVar); 
     } 
    }; 
}(); 
console.log(closure.secretVar); // Undefined 
closure.msg(); // Secret 

我覺得我有一個相當不錯的把握,讓我有能力控制如何訪問內部變量。

我現在遇到了這個問題

closure = function() { 
    var secretVar = ['Secret One','Secret Two']; 

    return { 
     "del" : function(modMe) { 
      modMe = secretVar; 
      modMe.slice(1,1); 
      console.log(modMe); 
     }(secretVar), 
     "secretVar" : function() { 
      console.log(secretVar); 
     } 
    }; 
}(); 
closure.del(); // Secret One 
closure.secretVar(); // Secret One 

我想closure.del()返回祕密之一,但我想secretVar到仍然不變,然而,事實並非如此。 del()函數修改引用而不是副本,並且我不確定如何獲取它以複製secretVar並修改它。

我猜這將是在

(function(y) { 
    //..Body that changes y 
})(secretVar) 

的形式,但我一直沒能得到那個工作。有任何想法嗎?

+3

我假設你的意思'slice',而不是'splice' – Robert 2010-11-09 19:30:38

回答

7

你的問題實際上與封閉無關。當你這樣做:

modMe = secretVar; 

你只是創建一個新的變量指向同陣列。你對一個人做的事情會反映在兩個變量中,因爲他們指的是同一件事。

如果要執行陣列上某種修飾(同時保持原有的),你需要先複製:

var copied = []; 
for(var i = 0; i < secretVar.length; i++){ 
    copied.push(secretVar[i]); 
} 

編輯:順便說一句,當你說你使用閉包爲了「保護變量」,你不能防止它們被執行閉包的返回函數修改。你只是這樣做的,以便這些變量不能從這些函數的範圍之外訪問。但是,在範圍內,比如當你執行切片時,變量就在那裏並且可以被該函數訪問,並且不僅僅因爲它是閉包而是「保護」的。

編輯2:如果你要經常複製數組,你可以通過創建一個合攏函數來完成複製爲你消除一些重複的刺激:

closure = function() { 
    var secretVar = 'Secret'; 
    var clone = function(){ 
     var clonedArr = []; 
     var length = secretVar.length; 
     for(var i = 0; i < length; i++){ 
      clonedArr.push(secretVar[i]); 
     } 
     return clonedArr; 
    } 

    return { 
     "msg" : function() { 
      var duplicate = clone(); 
     } 
    }; 
}(); 
+0

我希望有一個更直接的方式,而不是通過在陣列中的一切迭代。沒有這樣的運氣? – 2010-11-09 19:34:29

+0

迭代確實是最好的選擇。但是你必須記住 - 如果你正在迭代的數組中的值是另一個對象(比如說一個嵌套數組),當你像上面那樣做一個頂級「複製」時,你仍然通過引用來複制嵌套數組,並且會看到這些副作用也是如此。基元(比如數字)和不可變的值(比如字符串)沒有這種行爲,只是更高級別的對象。 – Matt 2010-11-09 19:42:59

+0

顯然我們不知道你的完整用例場景,但是如果你要經常克隆數組,你可以爲克隆創建另一個閉包函數。請參閱上面的更新 – Matt 2010-11-09 19:50:33

0

羅伯特做了好評,還要注意closure.del不是函數,而是未定義的。再看看你的代碼。該函數會自動執行並且不會返回任何內容,因此del將不會有任何結果

​​

它一般是這樣的形式:

var a = function(b){ 
    console.log(b) 
}('input'); 

console.log(typeof a); // undefined 
a(); // error: a is not a function 
+0

是的,我知道它不會那樣工作,但那是我試圖讓它工作的,它失敗了:P – 2010-11-09 19:36:50

+0

即使它返回了一些東西,它也不是一個函數。 – Harmen 2010-11-09 19:38:33

0

function(modMe) { ... }(secretVar)表達實際上是返回一個值,而不是一個功能,因爲你正在執行的功能。再加上馬特的答案,你需要:

  1. 取下表達(secretVar)組件還有modMe參數 - 功能已經訪問了secretVar反正。
  2. 實際上在處理之前複製數組。看到馬特的回答。
1

非常接近 - 的形式是:

(function(y) { 
    return function() { 
     // that changes y 
    }; 
})(secretVar) 

注:這仍然將傳遞一個參考,任何破壞或改變操作仍然會影響secretVar。如果你想避免改變它,你需要做一個secretVar的深層副本。

SEE:http://jsfiddle.net/B3ryr/2/

+1

如果你的內在功能修改了secretVar,你仍然會有副作用。切片返回一個新的數組,所以在這些情況下它仍然未被修改。所以,根據他的使用情況,這可能會或可能不是他所追求的。 – Matt 2010-11-09 19:46:14

+0

當我從'alert()'中移除'[0]'時,我得到'['A','B']',所以y似乎沒有被修改...... hmm – Robert 2010-11-09 19:47:13

+0

@ Robert查看JS的slice的定義 - 它返回數組的選定切片部分的新副本。 http://www.w3schools.com/jsref/jsref_slice_array.asp。它不會修改原始數組。 – Matt 2010-11-09 19:49:09