2011-12-25 14 views
11

C'è un modo per avere una funzione pubblica dal modello di modulo che accede dinamicamente alle variabili private? test1 mostra cosa intendo con "accesso dinamico", ma con variabili pubblicheÈ possibile accedere in modo dinamico a variabili private in un modello di modulo?

var x = (function(){ 
    var x=0, y=2, z=5; 

    return { 
     toast: 123, 
     test1: function(arg){ 
      return this[arg]; 
     }, 
     test2: function(){ 
      // ?? 
     } 
    }; 
}()); 

console.log(x.test1("toast")); // 123 
console.log(x.test2("y")); // should return 2 

ho finito con la creazione di una sola variabile privata (un oggetto) memorizzare le mie variabili private quindi ero in grado di accedervi come quello

privateVarStore[privateVarName] 

Ma esiste un'altra soluzione?

risposta

9

DEMO

Sì.

dispiace deludervi Adam Rackis ma lo si può fare con (la male) eval:

var x = (function(){ 
    var x=0, y=2, z=5; 

    return { 
     toast: 123, 
     test1: function(arg){ 
      return this[arg]; 
     }, 
     test2: function(a){ 
      return eval(a) 
     } 
    }; 
}()); 

console.log(x.test1("toast")); // 123 
console.log(x.test2("y")); // should return 2 -> does return 2 

Questa è una di quelle poche eccezioni nelle quali utilizzare eval.

EDIT, come da Hans B PUFAL suggerimento (commento), si può e si deve convalidare il parametro test2 come segue:

test2: function(a){ 
    return /^[$_a-z][$_a-z0-9]*$/i.test (a) ? eval(a) : undefined; 
} 
+3

Per evitare problemi di sicurezza, sarebbe consigliabile aggiungere una convalida che il parametro per test2 sia effettivamente una variabile semplice: return/^ [$ _ a-z] [$ _ a-z0-9] * $/i.test (a)? eval (a): non definito; – HBP

+0

@HansBPUFAL: ottima idea! Sarò sicuro di aggiungerlo – qwertymk

+1

+1, ma posso suggerire un'idea di convalida alternativa: se definisci un oggetto che elenca quale delle variabili private è accessibile tramite la funzione pubblica, come 'var accessList = {" x " : true, "y": true}; 'quindi in' function test2 (a) 'puoi dire' return accessList [a]? eval (a): undefined; '- il vantaggio è che non solo fornisce sicurezza riguardo a quali stringhe possono essere passate a valutazione, ma ti permette di definire altre variabili veramente private a cui non è possibile accedere tramite' test2() ' . – nnnnnn

7

No (almeno non senza ricorrere a eval, per risposta di qwertymk).

y non è una proprietà di x (considerare nominare questo oggetto qualcosa di meglio di x per evitare confusione con la variabile locale x). y è una variabile locale su cui i metodi di x hanno formato una chiusura.

qualsiasi dei metodi di x s' possono accedere y, ma non dicendo this.y, ma piuttosto accedendo y direttamente.

Anche in questo caso, non è una proprietà del proprio oggetto x. È solo una variabile locale nella funzione che ha creato x, causando così i metodi di x per formare una chiusura su di esso.

Quindi, per ottenere test2 per tornare y, basta fare:

test2: function(){ 
    return y; 
} 

di creare un metodo che consente di accedere variabili private, prendere in considerazione qualcosa di simile:

var x = (function() { 
    var privateMembers = { x: 0, y: 2, z: 5 }; 

    return { 
     getPrivate: function (name) { 
      return privateMembers[name]; 
     }, 
     toast: 123, 
     test1: function (arg) { 
      return this[arg]; 
     }, 
     test2: function() { 
      // ?? 
     } 
    }; 
})(); 

E then

alert(x.getPrivate("y")); //alerts 2 

Partenza this fiddle

+0

come si dovrebbe consigliare Tim per risolvere il codice mancante nella 'test2()' ? – mauris

+0

ottima risposta, ma quella era la mia soluzione alternativa (creando un singolo oggetto privato per accedere alle mie variabili private nella funzione pubblica), mi stavo chiedendo se c'è un altro (più bello) modo di farlo? –

+0

@Tim - non che io possa pensare. Personalmente, penso che la via sopra sia più bella :) –

Problemi correlati