18

I'm new to node and javascript and have been banging my head on the following. I've created an object as follows:

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

I have a function where I query mongodb, and loop through the results, attempting to load an array of subscribers, which I've declared as:

var s = Subscriber;
var subscribers = [];

The loop looks like this:

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

After each call to subscribers.push(s), the array has the correct number of elements, but all elements match the last values for s, like this (with two different users being pulled from the DB):

[ { userID: 4fc53a71163006ed0f000002,
email: 'test@test.com',
name: 'undefined undefined',
stage: 'new',
poster: false,
canEmail: true },
  { userID: 4fc53a71163006ed0f000002,
email: 'test@test.com',
name: 'undefined undefined',
stage: 'new',
poster: false,
canEmail: true } ]

Pushing a single element of s rather than the whole object seems to be fine. I added the "foo" array as a test, and it works fine:

Heres foo now: [ 'email1@foo.com', 'test@test.com' ]

What is going on here?!?!??!

4

2 回答 2

24

问题不在于 the 的push方法,而在于Array.prototype您的绑定。s您在块中的每次迭代中都修改了相同的对象,async.foreach这实际上与之前定义的对象相同Subscriber

首先,您应该将s变量的声明移至 foreach 块。

而且如果你想创建一个具有默认值的对象,它应该是 a function,它返回一个新对象:

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

然后你可以Subscriber像这样实例化一个对象:

var s = Subscriber();

有关更多解释,请参阅此答案MDN 上的 Closures 。

于 2012-06-07T13:24:29.710 回答
2

在推入数组之前克隆对象也解决了这个问题。

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

获取https://www.npmjs.com/package/clone

于 2016-10-16T18:29:01.337 回答