Array.push() делает все элементы одинаковыми при нажатии объекта

Я новичок в node и javascript, и я стучал головой по следующему. Я создал объект следующим образом:

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

У меня есть функция, где я запрашиваю mongodb и просматриваю результаты, пытаясь загрузить массив подписчиков, который я объявил как:

var s = Subscriber;
var subscribers = [];

Цикл выглядит следующим образом:

//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);
                }

После каждого вызова subscription.push массив имеет правильное количество элементов, но все элементы соответствуют последним значениям s, как это (с двумя разными пользователями, которые вытаскиваются из БД):

[ { 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 } ]

Нажатие одного элемента s, а не всего объекта, кажется, будет прекрасным. Я добавил массив "foo" в качестве теста, и он отлично работает:

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

Что здесь происходит?!?!??!

Ответ 1

Проблема не в методе push Array.prototype, а в ваших привязках. Вы модифицируете один и тот же объект s на каждой итерации в вашем блоке async.foreach, который фактически является тем же объектом, что и ранее определенный Subscriber.

Сначала вы должны переместить объявление переменной s в блок foreach.

А также, если вы хотите создать объект со значениями по умолчанию, это должен быть function, который возвращает новый объект:

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

А затем вы можете создать экземпляр объекта Subscriber следующим образом:

var s = Subscriber();

См. этот ответ или закрытие MDN для более подробного объяснения.

Ответ 2

Клонирование объекта перед вводом в массив также решает проблему.

temp = clone(s);
subscribers.push(temp);

Получить https://www.npmjs.com/package/clone

Ответ 3

Вы должны копировать подписчика каждый раз. В противном случае вы каждый раз изменяете один и тот же объект. Просто используйте s = copy(Subscriber)