我在创建对象数组的副本时遇到问题。我无法获得指向新的独立数组的新引用。
function OBJ1(name, tags) {
this.myname = name;
this.mytags = tags;
this.myvalue = 0;
}
function OBJ2(arg1) {
this.arg1 = arg1;
this.myarray = [];
}
var OBJ1_array = [];
var result_array2 = null;
var result;
OBJ1_array = createarray1();
for (i = 0; i < 2; i++) {
result = createarray2();
}
function createarray1() {
var myarray = [];
myarray.push(new OBJ1("NAME", [1, 2, 3]));
myarray.push(new OBJ1("others", [1, 2, 3]));
myarray.push(new OBJ1("total", [1, 2, 3]));
return myarray;
}
function createarray2() {
var newarray = $.extend(true, [], OBJ1_array); // newarray should refer to a new array, not the same one as OBJ1_array
OBJ1_array[0].myname = "CHANGED";
console.log("categories", JSON.parse(JSON.stringify(OBJ1_array)));
console.log("newarray", JSON.parse(JSON.stringify(newarray)));
}
输出:
testscript.js:45 categories (3) [{…}, {…}, {…}]0: {myname: "CHANGED", mytags: Array(3), myvalue: 0}1: {myname: "others", mytags: Array(3), myvalue: 0}2: {myname: "total", mytags: Array(3), myvalue: 0}length: 3__proto__: Array(0)
testscript.js:46 newArray (3) [{…}, {…}, {…}]0: {myname: "CHANGED", mytags: Array(3), myvalue: 0}1: {myname: "others", mytags: Array(3), myvalue: 0}2: {myname: "total", mytags: Array(3), myvalue: 0}length: 3__proto__: Array(0)
我希望OBJ1_array[0].myname="CHANGED";
对新创建的数组newArray
没有影响。
我尝试过但不起作用的事情:
var newArray = OBJ1_array.map(a => ({...a}));
var newarray=$.extend(true,[],OBJ1_array);
我该如何解决这个问题?
答案 0 :(得分:4)
$.extend
文档说:
未定义的属性不会被复制。但是,将从对象原型继承的属性复制过来。 通过
new MyCustomObject(args)
构造的对象的属性或内置JavaScript类型(例如Date或RegExp)不会被重构,它们将在结果对象或数组中显示为纯对象。
这意味着其中具有所有普通对象的数组将被深度合并/复制。但是,将不会重建使用new
关键字创建的对象。这使我们处于以下情况:
数组复制工作得很好,但是由于数组元素是使用new
关键字创建的,因此它们不会进一步合并。更改数组本身(推动,弹出等)时,您会看到数组确实是副本。
这里的问题是,您访问数组中的元素之一并更改对象(使用new
关键字创建)。这两个数组仍指向同一对象,因此,从另一个持有相同对象引用的数组中读取时,您也会看到此更改。
要解决此问题,您还必须make a copy数组中的每个对象。根据您的用例,您可能可以使用Object.assign
或Object.create
在盲目使用它们之前先阅读文档。
我还创建了一个您遇到的问题的最小示例,以使您对问题有更好的了解。
// setup
var array1, array2, array3, array4;
function Dummy(name) { this.name = name }
// test #1 - using plain objects
array1 = [{ name: 'Foo' }];
array2 = $.extend(true, [], array1);
array1[0].name = 'Bar';
console.log(array1[0].name, array2[0].name);
// test #2 - using the `new` keyword
array3 = [new Dummy('Foo')];
array4 = $.extend(true, [], array3);
array3[0].name = 'Bar';
console.log(array3[0].name, array4[0].name);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
答案 1 :(得分:1)
问题出在您的循环和 OBJ1函数中。第一次 OBJ1_array 没问题,但是当您第二次出现时,其值已经改变。
您可以尝试此代码
function OBJ1(name, tags) {
return {myname:name, tags:tags}
//this.myvalue = 0;
}
function OBJ2(arg1) {
this.arg1 = arg1;
this.myarray = [];
}
var OBJ1_array = [];
var result_array2 = null;
var result;
OBJ1_array = createarray1();
for (i = 0; i < 2; i++) {
let tempArr = $.extend(true, [], OBJ1_array);
result = createarray2();
OBJ1_array = tempArr;
}
function createarray1() {
let myarray = [];
myarray.push(new OBJ1("NAME", [1, 2, 3]));
myarray.push(new OBJ1("others", [1, 2, 3]));
myarray.push(new OBJ1("total", [1, 2, 3]));
return myarray;
}
function createarray2() {
let newarray =$.extend(true, [], OBJ1_array);// newarray should refer to a new array, not the same one as OBJ1_array
OBJ1_array[0].myname = "CHANGED";
console.log("categories", JSON.parse(JSON.stringify(OBJ1_array)));
console.log("newarray", JSON.parse(JSON.stringify(newarray)));
}
答案 2 :(得分:0)
更新了答案。实现所需目标的最简单方法是将JSON.stringify
与JSON.parse
一起使用,以创建对象数组的未链接副本。
const OBJ1 = (name, tags) => ({
myname: name,
mytags: tags,
myvalue: 0,
})
function createarray1() {
var myarray=[];
myarray.push(OBJ1("NAME", [1,2,3]));
myarray.push(OBJ1("others", [1,2,3]));
myarray.push(OBJ1("total", [1,2,3]));
return myarray;
}
const arr = createarray1()
// here you create a copy of array
const newArr = JSON.parse(JSON.stringify(arr))
// apply changes directly to the copy
newArr[0].myname = 'Something else'
console.log(newArr)
console.log(arr)
答案 3 :(得分:0)
数组和对象是引用类型,这意味着当您通过赋值进行复制时,您只是在复制引用而不是底层数组/对象。就您而言,在复制数组时,您将复制所有对象引用,这些引用仍将指向原始数组中的对象。您还需要克隆对象才能使其正常工作。
使用Array.map()
遍历数组并复制每个项目。
使用Object.create()
对每个对象进行浅表克隆。该函数采用原型和属性描述符来创建新对象。您可以使用Object.getPrototypeOf()
Object.getOwnPropertyDescriptors()
向其传递输入对象的原型和属性描述符。
function OBJ1(name) {
this.myname = name;
}
const array1 = [new OBJ1("NAME")];
const array2 = array1.map(obj =>
Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)
);
array2[0].myname = 'Jack';
console.log(array1[0].myname);
console.log(array2[0].myname);
答案 4 :(得分:0)
我认为您需要对对象进行深度克隆。请使用以下功能
function clone(src) {
var ret=(src instanceof Array ? [] : {});
for(var key in src)
{
if(!src.hasOwnProperty(key)) { continue; }
var val=src[key];
if(val && typeof(val)=='object') { val=clone(val); }
ret[key]=val;
}
return ret;
}
function OBJ1(name, tags) {
this.myname = name;
this.mytags = tags;
this.myvalue = 0;
}
function OBJ2(arg1) {
this.arg1 = arg1;
this.myarray = [];
}
var OBJ1_array = [];
var result_array2 = null;
var result;
OBJ1_array = createarray1();
for (i = 0; i < 2; i++) {
result = createarray2();
}
function createarray1() {
var myarray = [];
myarray.push(new OBJ1("NAME", [1, 2, 3]));
myarray.push(new OBJ1("others", [1, 2, 3]));
myarray.push(new OBJ1("total", [1, 2, 3]));
return myarray;
}
function createarray2() {
var newarray = clone(OBJ1_array) ; // newarray should refer to a new array, not the same one as OBJ1_array
OBJ1_array[0].myname = "CHANGED";
console.log("categories", JSON.parse(JSON.stringify(OBJ1_array)));
console.log("newarray", JSON.parse(JSON.stringify(newarray)));
}
更简单的方法
var cloneOfOBJ1_array = JSON.parse(JSON.stringify(OBJ1_array));
答案 5 :(得分:-1)
const newArray = myArray.map(a => Object.assign({}, a));
或更短,spread syntax
const newArray = myArray.map(a => ({...a}));