返回数组时对象数组的对象属性发生变化
Object array's object properties changing when returning array
我有一个函数可以操作和创建一个对象数组,并为数组中的每个项目添加一个 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;
};
如果调用正确,代入 choices
和 currentQueue
的值(currentQueue
也可以是一个空数组),如下所示,函数 returns 一个数组,这是有意的,但出于某种原因,它里面的每个对象上的 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
正确添加到每个对象中。返回数组中的每个对象都应该有 i + 1
的 position
,但它似乎是从 1 到 10 的某个随机数 - 有些对象甚至具有相同的 position
。
我试过了:
- 将
position
重命名为其他名称,以防 JavaScript 已在使用该名称
- 确保在将对象
.push
放入数组之前和之后将正确的 position
添加到对象中。
这让我很困惑。将不胜感激。
我能够想出以下内容。这是有效的,因为我避免使用 for/while 循环,它在 JS 中有引用 "gotchas",你在使用它更新值时需要注意。
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)
};
您正在将引用推入数组,因此每次更新 choice.position 时,数组中对同一选项的所有引用都将获得相同的位置值。
要解决此问题,请复制 choice 对象,更新其位置并将其推入数组,例如
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;
},{});
}
如果您想了解更深入的内容,这里有一百万个关于 "how to copy an object" 的问题和答案。
正如 RobG 已经说过的,您正在推送对 array.So 的引用,创建您的选择对象的副本,然后推送到您的数组。使用 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;
}
我有一个函数可以操作和创建一个对象数组,并为数组中的每个项目添加一个 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;
};
如果调用正确,代入 choices
和 currentQueue
的值(currentQueue
也可以是一个空数组),如下所示,函数 returns 一个数组,这是有意的,但出于某种原因,它里面的每个对象上的 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
正确添加到每个对象中。返回数组中的每个对象都应该有 i + 1
的 position
,但它似乎是从 1 到 10 的某个随机数 - 有些对象甚至具有相同的 position
。
我试过了:
- 将
position
重命名为其他名称,以防 JavaScript 已在使用该名称
- 确保在将对象
.push
放入数组之前和之后将正确的position
添加到对象中。
这让我很困惑。将不胜感激。
我能够想出以下内容。这是有效的,因为我避免使用 for/while 循环,它在 JS 中有引用 "gotchas",你在使用它更新值时需要注意。
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)
};
您正在将引用推入数组,因此每次更新 choice.position 时,数组中对同一选项的所有引用都将获得相同的位置值。
要解决此问题,请复制 choice 对象,更新其位置并将其推入数组,例如
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;
},{});
}
如果您想了解更深入的内容,这里有一百万个关于 "how to copy an object" 的问题和答案。
正如 RobG 已经说过的,您正在推送对 array.So 的引用,创建您的选择对象的副本,然后推送到您的数组。使用 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;
}