2012-06-07 2 views
9

Sono nuovo al nodo e javascript e ho sbattuto la testa su quanto segue. Ho creato un oggetto come segue:Array.push() rende tutti gli elementi uguali quando si preme un oggetto

var Subscriber = { 
'userID': String, 
'email': String, 
'name': String, 
'stage': String, 
'poster': Boolean, 
'canEmail': Boolean, 
'stage': String, } 

Ho una funzione in cui mi interrogo MongoDB, ed il ciclo attraverso i risultati, il tentativo di caricare una serie di abbonati, che ho dichiarato come:

var s = Subscriber; 
var subscribers = []; 

il ciclo aspetto:

//load array of users that are subscribed to the group 
     async.forEach(g.subscribers, function(item, callback) {  
      //load user document for this user 
      User.findOne({ _id: item}, function(err, u) { 
       if(!err && u) {     
        //var s = new Subscriber(); 
        console.log('Sub load, found user %s, building array item', u.email); 
        console.log('Subs @ loop start'); 
        console.log(util.inspect(subscribers)); 

        console.log('Heres foo: ' + util.inspect(foo)); 


        s.userID = u._id; 
        s.email = u.email; 
        s.name = u.firstName + ' ' + u.lastName; 
        s.stage = u.stage; 
        s.poster = false; //we're just loading subscribers at this point' 
        if(s.stage != 'new') s.canEmail = true; 

        //push new subscriber onto the array 
        console.log('Pushing ' + util.inspect(s)); 
        subscribers.push(s); 

        console.log('At end ' + util.inspect(subscribers)); 

        foo.push(s.email); 
        console.log('Heres foo now: ' + util.inspect(foo)); 

        callback(null, item); 
       } 

Dopo ciascuna chiamata alla subscribers.push (s), la matrice ha un corretto numero di elementi, ma tutti gli elementi corrispondenti gli ultimi valori di s, così (condue utenti diversi essere tirato dal DB):

[ { userID: 4fc53a71163006ed0f000002, 
email: '[email protected]', 
name: 'undefined undefined', 
stage: 'new', 
poster: false, 
canEmail: true }, 
    { userID: 4fc53a71163006ed0f000002, 
email: '[email protected]', 
name: 'undefined undefined', 
stage: 'new', 
poster: false, 
canEmail: true } ] 

spingendo un singolo elemento di s anziché l'intero oggetto sembra essere fine. Ho aggiunto la matrice "foo" come un test, e funziona bene:

Heres foo now: [ '[email protected]', '[email protected]' ] 

Che cosa sta succedendo qui ???!?!

+0

Cosa significa 'g.subscribers' assomigliare? – alessioalex

+2

Oggetti e matrici (che sono oggetti) vengono passati per riferimento in JavaScript. Se 's' è un oggetto, e lo stai riutilizzando cambiando solo le proprietà e quindi spingendo lo stesso oggetto sull'array in un ciclo, gli oggetti nell'array sono tutti riferimenti allo stesso oggetto. – Steve

+0

Grazie! Questo è stato molto utile. Stavo pensando che potrebbe essere qualcosa con riferimenti, ma non riuscivo a capirlo. Immagino che questo sia quello che succede quando sei ultimo lavoro di sviluppo è stato due decenni fa in linguaggi all'avanguardia come Pascal e C! – pat

risposta

13

Il problema non è con il metodo push dello Array.prototype ma con i collegamenti. Si sta modificando lo stesso oggetto s in ogni iterazione nel proprio blocco async.foreach che è in realtà lo stesso oggetto del precedente Subscriber.

Per prima cosa è necessario spostare la dichiarazione della variabile s nel blocco foreach.

E anche se si desidera creare un oggetto con valori di default, dovrebbe essere un function, che restituisce un nuovo oggetto:

function Subscriber() { 
    return { 
    'userID': '', 
    'email': '', 
    'name':  '', 
    'stage': '', 
    'poster': false, 
    'canEmail': false, 
    'stage': '' 
    }; 
}; 

e poi si può istanziare un oggetto Subscriber come questo:

var s = Subscriber(); 

Vedere this answer o Closures on MDN per ulteriori spiegazioni.

-1

È necessario copiare l'utente ogni volta. Altrimenti si modifica lo stesso oggetto ogni volta. Basta usare s = copy(Subscriber)

+0

'copia' non è definito nell'ambiente node.js. –

Problemi correlati