【问题标题】:Add new element in existing object在现有对象中添加新元素
【发布时间】:2025-12-30 05:20:13
【问题描述】:

我正在使用 node.js。

在向客户端发送响应之前,我必须在对象中添加新元素。

user.getMatch(req.user, function(err, match){

        for( k=0; k<match.length; k++){
            var userId = {
                id : match[k].match_id  
            };
            var user = new User(userId);
            console.log('k: ' + k);
            user.getUserInfo(function(err2, info){
                console.log('k here: ' + k);
                if(info){
                    match[k].foo = info[0].foo;
                }
            });
        }

        var response = {
                data    : match
            };
        res.json(response);
});

我想将 user.getUserInfo 中的元素“foo”添加到 user.getMatch 返回的对象“match”中。然后将所有数据作为响应发送给客户端。

但它出错了,因为 user.getUserInfo 内部的“k”不等于外部的“k”。 我不知道为什么两个“k”不相等。

以及在执行循环后我将如何向客户端发送响应。

感谢您的帮助!

【问题讨论】:

  • 由于 javascript 是异步的,您将获得 k 的随机值。而不是为此使用 for 循环,您可以使用异步模块
  • @V31,为什么是随机的?调用回调时,k 将始终等于 match.length

标签: javascript node.js javascript-objects


【解决方案1】:

这里有一些问题:

首先,k 没有定义,所以你使用的 k 实际上是一个全局变量,这不是你想要的。您需要将其定义为 'var k'。

其次,您传递给user.getUserInfo() 的回调函数(可能)在未来某个未知时间执行。此时,您的循环for (k ... 已经完成,因此k 变量已经有了一个新值,因为它是您调用user.getUserInfo() 时的值。这是棘手的部分:回调函数中的代码将使用 k 的最新值。它不会使用创建函数时 k 的值。

您可以通过向回调函数添加参数并使用.bind 方法将 k 绑定到它来解决此问题:

user.getMatch(req.user, function(err, match){

  var k;
  for(k=0; k < match.length; k++){
    var userId = {
      id : match[k].match_id  
    };
    var user = new User(userId);
    console.log('k: ' + k);

    var callback = function(k, err2, info){
      console.log('k here: ' + k);
      if(info){
        match[k].foo = info[0].foo;

      }
    }.bind(null, k);
    user.getUserInfo(callback);
  }

  var response = {
    data: match
  };
  res.json(response);
});

另外,最好使用.forEach 迭代数组:

user.getMatch(req.user, function(err, match){

  match.forEach(function(curr) {
    var userId = {
      id : curr.match_id  
    };
    var user = new User(userId);

    user.getUserInfo(function(err2, info){
      if(info){
        curr.foo = info[0].foo;
      }
    }
  });

  var response = {
    data: match
  };
  res.json(response);
});

虽然Array.forEach 可以在迭代中为您提供当前索引,但这不再需要。只需使用 curr 值(它为您提供迭代中的当前元素)。

最后,我认为这里的代码很可能会在所有user.getUserInfo() 调用都执行完毕之前发送响应。要实现这一点,您需要知道所有user.getUserInfo() 何时完成。这可以通过添加变量numLeft 来实现,每次我们获得用户信息时该变量都会递减。当此变量为零时,我们知道所有getUserInfo() 都已完成,因此可以安全地发回响应。

user.getMatch(req.user, function(err, match) {

  var numLeft = match.length;

  match.forEach(function(curr) {
    var user = new User({
      id : curr.match_id  
    });

    user.getUserInfo(function(err2, info){
      if(info) {
        curr.foo = info[0].foo;
      }
      --numLeft;
      if (numLeft == 0)
        res.json({ data: match });
    }
  });
});

【讨论】:

  • 我想在构造 User 对象时传输 k 会更好。只需添加一个新参数,每个对象都会知道它应该使用的数组索引。
  • 但我遇到了另一个问题.. 它在添加“foo”元素之前向客户端发送响应。所以在对客户端的响应中,它只发送来自“match”的对象,没有“foo”元素。
  • @user3094292 请查看我回复中的最后一个 sn-p(刚刚添加) - 它解决了这个问题。
  • 感谢@Fishy 和 Itay Maman。我使用了两者或您的答案。感谢您的大力帮助。干杯!但是我不知道我会将哪一个标记为已接受,因为你们俩都有很好的答案。无论如何,再次感谢!
  • @user3094292 如果答案很好,如果您接受或支持它会很有帮助!!!
【解决方案2】:

当您说“k inside and outside”时,您是指user.getUserInfo(function(err2, info){}) 的内部和外部吗?
我不确定您的上下文,但是我可以想到两件事

  1. 由于函数“function(err2, info)”是一个回调并且异步执行,因此在 getUserInfo 中使用 k 的上下文/堆栈是完全不同的。所以尝试在调用时传递 k 即

    user.getUserInfo(function(err2, info, k){})。这应该工作

  2. 尝试在你想要使用的闭包中声明 k 即 var k



更新问题的另一部分
“但是我遇到了另一个问题。它在添加“foo”元素之前向客户端发送了响应。因此,在对客户端的响应中,它只发送来自“匹配”的对象,而没有“foo”元素。”
这又是因为您在获取用户信息中的代码是异步执行的。 为此,您需要保留一个全局标志或尝试从 getUserInfo 中发送响应 即

var mathLen = match.length;
user.getUserInfo(function(err2, info,k,mathLen)

{
                console.log('k here: ' + k);
                if(info){
                    match[k].foo = info[0].foo;
                }
                if(k==mathLen)
                {
                 var response = {
                    data    : match
                };
            res.json(response);
                     }

            });

【讨论】:

  • @user3094292 如果答案很好,如果您接受或支持它会很有帮助!!!