复制对象数组

时间:2019-03-08 09:53:30

标签: javascript jquery arrays object

我在创建对象数组的副本时遇到问题。我无法获得指向新的独立数组的新引用。

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

我该如何解决这个问题?

6 个答案:

答案 0 :(得分:4)

$.extend文档说:

  

未定义的属性不会被复制。但是,将从对象原型继承的属性复制过来。 通过new MyCustomObject(args)构造的对象的属性或内置JavaScript类型(例如Date或RegExp)不会被重构,它们将在结果对象或数组中显示为纯对象。

这意味着其中具有所有普通对象的数组将被深度合并/复制。但是,将不会重建使用new关键字创建的对象。这使我们处于以下情况:

数组复制工作得很好,但是由于数组元素是使用new关键字创建的,因此它们不会进一步合并。更改数组本身(推动,弹出等)时,您会看到数组确实是副本。

这里的问题是,您访问数组中的元素之一并更改对象(使用new关键字创建)。这两个数组仍指向同一对象,因此,从另一个持有相同对象引用的数组中读取时,您也会看到此更改。

demonstration image

要解决此问题,您还必须make a copy数组中的每个对象。根据您的用例,您可能可以使用Object.assignObject.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.stringifyJSON.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)

使用Object.assign

解决了对象数组的克隆
const newArray = myArray.map(a => Object.assign({}, a));

或更短,spread syntax

const newArray = myArray.map(a => ({...a}));