【问题标题】:Does Spreading create shallow copy?传播会创建浅拷贝吗?
【发布时间】:2018-10-07 15:14:28
【问题描述】:

按照here给出的例子,

let first:number[] = [1, 2];
let second:number[] = [3, 4];

let both_plus:number[] = [0, ...first, ...second, 5];
console.log(`both_plus is ${both_plus}`);
first[0] = 20;
console.log(`first is ${first}`);
console.log(`both_plus is ${both_plus}`);
both_plus[1]=30;
console.log(`first is ${first}`);
console.log(`both_plus is ${both_plus}`);

Spreading 显示一个深拷贝,因为所有三个数组都有自己的重复项,基于以下输出:

both_plus is 0,1,2,3,4,5
first is 20,2
both_plus is 0,1,2,3,4,5
first is 20,2
both_plus is 0,30,2,3,4,5

Documentation 说:传播会创建 firstsecond 的浅表副本。我怎么理解这个?

【问题讨论】:

  • [0, 1, 2, 3, 4, 5]。如果您所拥有的只是原始数据,您将无法真正判断副本是否深。
  • 不,传播语法不会创建或复制任何内容。创建新数组的是 数组字面量

标签: typescript ecmascript-6 deep-copy shallow-copy


【解决方案1】:

传播导致浅拷贝

const a = [{x: 1}, {y: 1}];
const b = a;

const c = [...a, ...b];
console.log(c); // [{x: 1}, {y: 1}, {x: 1}, {y: 1}]

a[1]['y'] = 5;
console.log(c); // [{x: 1}, {y: 5}, {x: 1}, {y: 5}]

【讨论】:

    【解决方案2】:

    在您的情况下,浅拷贝和深拷贝是相同的。对于仅包含基元的数组,它们将始终相同。只有当您的数组包含其他对象时,您才会注意到差异。

    Javascript 是按值传递的,所以当一个数组被浅拷贝时(例如使用spread),原始数组中的每个值都会被复制到新数组中。对于原语,直接复制该值,对其进行的更改对原始值没有影响。

    但是,当数组包含对象时,每个值本身就是对其他对象的引用。因此,即使引用已被复制到一个新数组,它仍然指向与原始数组中的引用相同的东西。所以虽然改变新数组不会改变原始数组,但改变数组元素会影响原始数组。

    这是一个例子:

    const objArray = [{foo: "bar"}];
    const shallowCopy = [...objArray];
    
    // Changing the array itself does not change the orignal. Note the
    // original still only has one item, but the copy has two:
    shallowCopy.push({foo: "baz"});
    console.log("objArray after push:", objArray);
    console.log("shallowCopy after push:", shallowCopy);
    
    // However, since shallowCopy[0] is a reference pointing to the same object
    // as objArray[0], mutating either will change the other:
    shallowCopy[0].foo = "something else";
    console.log("objArray after mutation:", objArray);
    console.log("shallowCopy after mutation:", shallowCopy);

    【讨论】:

      【解决方案3】:

      浅拷贝意味着来自firstsecond 的所有元素仅被添加到新数组,即新副本中。深拷贝意味着firstsecond 中的所有元素首先被复制然后添加到新数组中。

      区别在于元素本身是否在添加到新数组之前被复制到新对象中。

      使用原语,例如数字,实际上不可能说明差异,但如果使用对象,差异就很明显了。

      假设你有这样的事情:

      let first = [{foo: 'bar'}];
      let second = [{fizz: 'buzz'}];
      let both = [...first, ...second];
      

      由于传播导致浅拷贝,您可以期望相关对象通过相等性测试:

      first[0] === both[0]; // true
      second[0] === both[1]; // true
      

      但如果传播导致深拷贝,您会认为相等性测试会失败:

      first[0] === both[0]; // false
      second[0] === both[1]; // false
      

      【讨论】:

      • 在我的机器上,结果评估为first[0] === both[0]; // falsesecond[0] === both[1]; // true
      猜你喜欢
      • 2011-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      • 2013-04-06
      • 2013-08-23
      • 2015-01-13
      • 2011-09-05
      相关资源
      最近更新 更多