我可以使用解构来创建深拷贝吗?

Can I use Destructuring to create a deep copy?

基本上我想得到一个深拷贝,不会使用解构改变我的主要对象。

let a = {
    name: 'lala', 
  testArray: [1,2,3], 
  object: {
    name: 'object', 
    array: [4,5,6]
  }
};

const {name, testArray, object} =  a;

object.array = [...object.array, 0];
console.log(a.object.array);

let b = {
  object2: {
    name: 'object', 
    array: [4,5,6]
  }
};

const object2 =  {...b.object2};
object2.array = [...object2.array, 0];

console.log(b.object2.array);

我制作了一个 jsfiddle(为了更容易复制),提供了我编写的代码。

https://jsfiddle.net/5z71Lbja/

问题是,当我使用第一种方法(解构)更改 "child" 对象时,主对象的数组也会发生变化。第二种方法工作正常,但我很好奇我是否可以使用解构实现相同的结果。

你不能用解构创建新对象,不。您只能挑选出源上存在的值,不能对它们执行转换。 (你可以改变你使用的变量名,但你不能转换值。)我经常想,但你不能(至少,目前不能)。

有多种 jump-through-the-hoops 方法可以实现,但实际上最简单的方法是分别制作数组的浅表副本。

一个更简单的例子:

const obj = {
  foo: "bar",
  array: [1, 2, 3]
};

const {foo} = obj;
const array = obj.array.slice(); // or: = [...obj.array];

obj.array[0] = "one";
console.log(obj.array[0]); // "one"
console.log(array[0]);     // 1

直接是不行的

let { object } = a;
object = {...object}; // Object.assign({}, object); <<

object.array = [0, ...object.array, 0];

console.log(object.array); // [0, 4, 5, 6, 0]
console.log(a.object.array); // [4, 5, 6]

回答

您可以通过函数或直接使用 Proxy 对象来实现。


在 Destruct 期间使用函数:

Proxy对象取target对象,handler.

A handler 允许您设置某些条件,例如 getset,这些条件可以改变数据 returned 给用户的方式。为此,我们将使用 get

在下面的处理程序中,我们更改了 get 功能。我们检查 target[prop] return 是 Array 还是 Object。如果是这样,我们会在内存中创建一个副本并 return 代替引用。如果它不是 ArrayObject 我们简单地 return 原始值(字符串,数字等)

let copyHandler = {
  get: function( target, prop, receiver ) {
    let value = target[ prop ];
    if ( Array.isArray( value ) ) return value.slice( 0 );
    if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
    return value;
  }
}, getCopy = obj => new Proxy(obj, copyHandler);

利用 getCopy 函数作为我们的解构 middle-man,我们可以确定我们所有的值 return 新引用:

const {
  name,
  testArray,
  object
} = getCopy(a);


object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]

示例:

let copyHandler = {
  get: function( target, prop, receiver ) {
    let value = target[ prop ];
    if ( Array.isArray( value ) ) return value.slice( 0 );
    if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
    return value;
  }
}, getCopy = obj => new Proxy(obj, copyHandler);



let a = {
  name: 'lala',
  testArray: [ 1, 2, 3 ],
  object: {
    name: 'object',
    array: [ 4, 5, 6 ]
  }
};

const {
  name,
  testArray,
  object
} = getCopy(a);



object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]


或者,我们可以直接在 Declaration/Initialization/Reception:

直接在这个意义上意味着我们可以将对象设置为 return 仅在解构声明期间的副本。

我们通过使用 Proxy 和 middle-man 函数来执行与上述类似的操作。

注意: middle-man 函数不是必需的,但它有助于使事情井井有条。

let destructHandler = {
  get: function( target, prop, receiver ) {
    if(!this.received) this.received = new Set();

    let value = target[ prop ];
    if(this.received.has(prop)) return value;

    this.received.add(prop);

    if ( Array.isArray( value ) ) return value.slice( 0 );
    if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
    return value;
  }, destructable = obj => new Proxy(obj, destructHandler);

这里的区别是我们的 get 处理程序使用 Set 来确定 属性 是否已经被抓取过一次。

它会 return 在第一次请求引用时复制 属性(ArrayObject)。它仍然会 return 正常的任何原始值。

这意味着在 declaring/initialization/reception 对象上,您可以应用 destructable 代理,然后立即使用 destruct 从该对象中提取副本。

初始化示例代码:

let a = destructable({
  name: 'lala',
  testArray: [ 1, 2, 3 ],
  object: {
    name: 'object',
    array: [ 4, 5, 6 ]
  }
});

解构示例:

const {
  name,
  testArray,
  object
} = a;

object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]

示例:

let destructHandler = {
  get: function( target, prop, receiver ) {
    if(!this.received) this.received = new Set();
    
    let value = target[ prop ];
    if(this.received.has(prop)) return value;
    
    this.received.add(prop);
    
    if ( Array.isArray( value ) ) return value.slice( 0 );
    if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
    return value;
  }
}, destructable = obj => new Proxy(obj, destructHandler);


let a = destructable({
  name: 'lala',
  testArray: [ 1, 2, 3 ],
  object: {
    name: 'object',
    array: [ 4, 5, 6 ]
  }
});

const {
  name,
  testArray,
  object
} = a;
    object.array = [...object.array, 0];
    console.log(object.array); // [4,5,6,0]
    console.log(a.object.array); // [4,5,6]

希望对您有所帮助!编码愉快!

我认为可以尝试使用以下代码对对象进行深度复制,我使用了解构。

function deepcopy(obj) {
  let { ...data
  } = obj;
  let newObj = { ...data
  }

  // deleting one key (just to show that it doesn't affect original obj)
  delete newObj.a


  console.log("param obj ", obj);
  return newObj;
}
const obj = {
  a: 1,
  b: 2,
  c: 3
}
console.log("original obj ", obj);
console.log("copy newObj", deepcopy(obj));
console.log("original obj ", obj);

希望对您有所帮助!!! :)