2010-11-09 68 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