复制对象数组

问题描述 投票:1回答:6

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

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

我该如何解决这个问题?

javascript jquery arrays object
6个回答
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
投票

问题出在你的循环和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)));
}

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)

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

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

-1
投票

Object.assign解决了一系列对象的克隆问题

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

甚至更短的spread syntax

const newArray = myArray.map(a => ({...a}));
© www.soinside.com 2019 - 2024. All rights reserved.