返回数组时对象数组的对象属性发生了变化

时间:2016-02-18 06:08:20

标签: javascript arrays javascript-objects

我有一个函数可以操作和创建一个对象数组,并为数组中的每个项添加一个position键,但它似乎根本无法正常工作......

我的功能:

var fillQueue = function(choices, currentQueue) {
  var choice, i, positionInQueue, previousTitle, resultQueue;

  resultQueue = [];
  previousTitle = "";

  i = 0;

  while (i < 10) {
    positionInQueue = i + 1;
    console.log('Adding song to position ' + positionInQueue);

    if (currentQueue[i]) {
      previousTitle = currentQueue[i].title;
      currentQueue[i].position = positionInQueue;
      resultQueue.push(currentQueue[i]);
    } else {
      choice = choices[Math.floor(Math.random() * choices.length)];

      if (choice.title !== previousTitle) {
        previousTitle = choice.title;
        choice.position = positionInQueue;
        resultQueue.push(choice);
      } else {
        choice = choices[Math.floor(Math.random() * choices.length)];
        previousTitle = choice.title;
        choice.position = positionInQueue;
        resultQueue.push(choice);
      }
    }

    i++;
  }

  return resultQueue;
};

如果正确调用此方法,则替换为choicescurrentQueuecurrentQueue的值也可以是空数组),如下所示,该函数返回一个数组,这是预期的,但由于某种原因,请在其中的每个对象上用position个键进行固定。

var test = fillQueue([ {title: '1'}, {title: '2'}, {title: '3'}, {title: '4'} ], [ { title: '5', position: 1 } ]);

上述变量将包含:

[ { title: '5', position: 1 },
  { title: '1', position: 9 },
  { title: '3', position: 7 },
  { title: '1', position: 9 },
  { title: '2', position: 10 },
  { title: '2', position: 10 },
  { title: '3', position: 7 },
  { title: '1', position: 9 },
  { title: '1', position: 9 },
  { title: '2', position: 10 } ]

正如您所看到的,它没有正确地将position添加到每个对象中。返回数组中的每个对象都应该有position i + 1,但它似乎是1到10之间的一些随机数 - 有些对象甚至具有相同的position。< / p>

我尝试过:

  • position重命名为其他内容,以防它已被JavaScript使用
  • 确保在position之前和之后将正确的.push添加到对象中。

这让我很困惑。感谢您的帮助。

小提琴:https://jsfiddle.net/deansheather/jnw8jdf4/

3 个答案:

答案 0 :(得分:1)

您正在将引用推送到数组中,因此每次更新 choice.position 时,对数组中相同选项的所有引用都会获得相同的位置值。

要解决此问题,请复制选择对象,更新其位置并将其推入阵列,例如

if (choice.title !== previousTitle) {
        previousTitle = choice.title;
        newChoice = objCopyShallow(choice); // see below for copy function
        newChoice.position = positionInQueue;
        resultQueue.push(newChoice);
}

对于此应用程序,一个简单的复制功能是:

function objCopyShallow(obj) {
  return Object.keys(obj).reduce(function(acc, v) {
      acc[v] = obj[v];
      return acc;
    },{});
}

这里有一百万个问题和答案关于&#34;如何复制一个对象&#34;如果你想要更深层次的东西。

答案 1 :(得分:1)

正如RobG已经说过你正在推动你的数组的引用。所以创建你的选择对象的副本,然后推送到你的数组。使用clone()创建对象的副本 将您的任务更改为 choice = clone(choices[Math.floor(Math.random() * choices.length)]); 你完成了。

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

答案 2 :(得分:0)

我能够想出以下内容。这是因为我避免使用for / while循环,这些循环有参考&#34;陷阱&#34;在JS中,您需要注意何时使用它来更新值。

&#13;
&#13;
var fillQueue = function(choices, currentQueue) {
  // concat choices to end of currentQueue
  // create a new array instance with updated position property using .map
  // keep 10 elements from new array starting at index 0 
  return currentQueue.concat(choices).map( (e, i) => {
    return Object.assign({title:e.title, position:i+1});
  }).splice(0, 10)
};
&#13;
&#13;
&#13;