2013-02-09 18 views
15

Ho pensato che stavo iniziando a capire JavaScript piuttosto bene, ma chiaramente no. Lasciatemi spiegare il mio problema con un esempio. In primo luogo ho il seguente modulo definito:Creazione di più istanze di un modulo

var Test = function() { 
    var counter = 0; 

    function init() { 
     alert(counter); 
    } 

    return { 
     counter: counter, 
     init: init 
    } 
}; 

Ho quindi creare 2 casi:

var test1 = new Test(); 
var test2 = new Test(); 

Ora aggiornare la variabile del contatore (come è pubblico) e fare alcuni avvisi. Fin qui tutto bene.

alert(test1.counter); // Alerts 0 
test1.counter = 5; 
alert(test2.counter); // Alerts 0 
test2.counter = 10; 
alert(test1.counter); // Alerts 5 

Ora finalmente ho dire quanto segue:

test1.init(); // Alerts 0 
test2.init(); // Alerts 0 

Questo è il bit che non capisco. Perché questo avviso 0? Ho pensato che il primo avviso sarebbe stato 5 e il secondo 10.

Apprezzerei se qualcuno potesse spiegare come potrebbe funzionare quanto sopra o indicarmi la giusta direzione. Grazie

+4

scalare diversi tipi di variabili sono passati per valore piuttosto che per riferimento. Quindi 'return {counter: counter, ...}' copia solo il valore corrente 'var counter' e cambiando' this.counter'does non ha effetto su 'var counter'. –

risposta

11

Rimane 0 perché non si modifica la variabile all'interno di Test, si modifica l'oggetto restituito dalla funzione. counter viene mantenuto "privato" e solo una funzione in Test può accedervi.

var Test = function() { 
    var counter= 0; 

    function init() { 
      alert(counter); 
    } 
    function changeNum(n){ 
     counter = n;   //add a function inside `Test` so that it can 
    }       //access the variable 

    return { 
     counter: counter, 
     init: init, 
     changeNum: changeNum 
    } 
}; 

Ora funziona: http://jsfiddle.net/DerekL/pP284/

var test1 = new Test(); 
alert(test1.counter);   //0 
test1.init();     //0 
test1.changeNum(5); 
alert(test1.counter);   //5 
test1.init();     //5 

Per ulteriori informazioni, vedere JavaScript Closures.

+0

Mille grazie. Questo ha chiarito bene le cose. – nfplee

+0

E perché potrebbe essere Test sullo spazio globale disponibile per tutti gli script? – AntonioRomero

3

Non sono sicuro se hai fatto un errore nel tuo post, ma si potrebbe riscrivere il codice di cui sopra come segue

var Test = function() { 
    this.counter = 0; 
} 

Test.prototype.init = function() { 
    alert(this.counter); 
} 

var test1 = new Test(); 
var test2 = new Test(); 


test1.counter = 5; 
test2.counter = 10; 

test1.init(); // alerts 5 

test2.init(); // alerts 10 

Nel tuo esempio non si imposta il contatore di essere una proprietà su il tuo oggetto/funzione Test, piuttosto quando chiami test1.counter stai essenzialmente impostando una nuova proprietà che non esisteva prima e la tua funzione init non fa riferimento a quella proprietà.

Come la risposta di Dereks mostra, sembra che tu abbia leggermente confuso i due diversi modelli tra quello che segue la mia risposta e il suo.

5

Questo è accaduto:

  1. la funzione init() ha una chiusura sulla variabile counter, che è definita all'interno Test dell'ambito, in possesso di un riferimento ad esso.
  2. il ritorno dalla funzione Test() ha creato un nuovo oggetto, con un'altra variabile counter, impostata sul valore interno counter.
  3. Si aggiorna "un altro" counter, impostando test1.counter = X, ma init() conserva ancora un riferimento alla variabile originale.

Ecco perché vedi il vecchio valore.

+0

Grazie per il chiarimento extra. Ho assegnato a Derek la risposta semplicemente perché il suo è venuto prima del tuo e mi ha ugualmente aiutato. – nfplee

0

Ecco cosa farei:

function Test() { 
    this.counter = 0; 
    this.init = function() { console.log(this.counter); } 
}; 

var test1 = new Test(); 
var test2 = new Test(); 

console.log(test1.counter); //0 
test1.counter = 5; 
console.log(test2.counter); //0 
test2.counter = 10; 
console.log(test1.counter); //5 

test1.init(); //5 
test2.init(); //10 
Problemi correlati