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

ответ

7

Ваша проблема не имеет ничего общего с закрытием. Когда вы делаете:

modMe = secretVar; 

Вы просто создать новую переменную, указывающую на же массив. То, что вы делаете с одним, будет отражено в обеих переменных, поскольку они указывают на одно и то же.

Если вы хотите, чтобы выполнить какое-то изменения на массиве (при сохранении оригинала), вам нужно скопировать его первым:

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

Edit: Как и в стороне, когда вы говорите, что вы используете замыкание для «защиты переменных» вы не защищаете их от изменения возвращаемыми функциями, которые выполняли закрытие. Вы просто сделали это так, чтобы переменная была недоступна из-за пределов этих функций. Но внутри области, например, когда вы делаете свой фрагмент, переменная существует и доступна для этой функции и не является «защищенной» только потому, что она является закрытием.

Edit 2: Если вы собираетесь копировать массив часто, вы можете устранить некоторые раздражения итерации, создавая closured функцию, чтобы сделать копирование для вас:

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

Я надеялся, что там было более простым способом, а не перебирая все в массиве. Нет такой удачи? –

+0

Итерация - действительно лучший способ пойти. Но вы должны помнить - если значение в массиве, которое вы повторяете, является другим объектом (скажем, вложенным массивом), когда вы выполняете «копию» верхнего уровня, как показано выше, вы все еще копируете вложенный массив по ссылке и увидите побочные эффекты. Примитивы (такие как числа) и неизменяемые значения (например, строки) не имеют такого поведения, а только объекты более высокого уровня. – Matt

+0

, очевидно, мы не знаем сценарий вашего полного использования, но если вы собираетесь клонировать массив часто, вы можете создать еще одну закрытую функцию для клона. см. обновление выше – Matt

0

Роберт сделал Хороший комментарий, но также обратите внимание, что closure.del не является функцией, но не определено. Еще раз посмотрите на свой код. Функция автоматически выполняется и ничего не возвращает, поэтому del будет ничем.

var del = function(modMe) { 
    modMe = secretVar; 
    modMe.slice(1,1); 
    console.log(modMe); 
}(secretVar); 

Это вообще такая форма:

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

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

Да, я знаю, что это не сработает, но это была моя попытка заставить его работать, что было неудачно: P –

+0

Даже если он что-то вернет, это не будет функцией. – Harmen

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, у вас все равно будет побочный эффект. Slice возвращает новый массив, поэтому в этих обстоятельствах он не изменяется. Таким образом, в зависимости от его варианта использования, это может быть или не быть тем, чем он занимается. – Matt

+0

Я получаю '['A', 'B']' все еще, когда я удаляю '[0]' из 'alert()', поэтому y не кажется фактически измененным ... hmm – Robert

+0

@ Роберт видит определение slice для JS - он возвращает новую копию выбранной нарезанной части массива. http://www.w3schools.com/jsref/jsref_slice_array.asp. Он не изменяет исходный массив. – Matt

Смежные вопросы