Object.assign和对象传播之间的区别(使用[...]语法)?

时间:2017-08-25 20:07:49

标签: javascript ecmascript-6

我在这里有一些代码,我想知道它是相同的还是不同的。我很确定这些都是相同的,但我不确定我是否做得对。

let zoneComment = updatedMap[action.comment.zone]
        ? [...updatedMap[action.comment.zone]] : [];
let zoneComment = updatedMap[action.comment.zone]
          ? Object.assign([], updatedMap[action.comment.zone]) : [];

如果这些是相同的,那么我应该使用它还是重要的?我想使用最佳实践,如果你的观点更好,那么请说明。

3 个答案:

答案 0 :(得分:3)

在您的特定情况下,他们相同。

原因是你有一个数组,而不是一个对象。

在数组上执行...将展开数组中的所有元素(但不是属性)

执行Object.assign期望一个对象,所以它会将一个数组视为一个对象并将所有enumerable自己的属性复制到其中,而不仅仅是元素:



const a = [1, 2, 3];
a.test = 'example';

const one = [...a] // [1, 2, 3];
const two = Object.assign([], a); // { '0': 1, '1': 2, '2': 3, 'test': 'example' }

console.log('\none');
for (let prop in one) {
  console.log(prop);
}

console.log('\ntwo');
for (let prop in two) {
  console.log(prop);
}




但是,如果您将对象上应用的...运算符与Object.assign进行比较,则它们基本相同:



// same result
const a = { name: 'test' }
console.log({ ...a })
console.log(Object.assign({}, a))




...总是创建一个新对象,但Object.assign也允许您改变现有对象。



// same result
const a = { name: 'test' }
const b = { ...a, name: 'change' };

console.log(a.name); // test
Object.assign(a, { name: 'change'})
console.log(a.name); // change




请记住,Object.assign已经是语言的一部分,而对象传播仍然只是一个提案,需要使用像babel这样的工具进行预处理步骤(转换)。

答案 1 :(得分:1)

你的问题确实起泡到了:

[...arr]是数组时,Object.assign([], arr)arr是否会提供相同的结果?

答案是:通常,是的,但是:

  • 如果arr是一个稀疏数组,其最后一个插槽没有值,则结果的length属性在两种情况下都不相同:扩展语法将保持不变length属性的值相同,但Object.assign将生成一个length的数组,该数组对应于上次使用的插槽的索引加一。

  • 如果arr是一个稀疏数组(就像你使用Array(10)得到的那样),那么扩展语法将在这些索引处创建一个undefined值的数组,所以它会是稀疏数组。另一方面,Object.assign会将这些广告位置保留为空(不存在)。

  • 如果arr具有自定义可枚举属性,则它们将由Object.assign复制,但不会通过传播语法复制。

以下是前两个差异的演示:



var arr = ["abc"]
arr[2] = "def"; // leave slot 1 empty
arr.length = 4; // empty slot at index 3

var a = [...arr];
var b = Object.assign([], arr);
    
console.log(a.length, a instanceof Array); // 4, true
console.log(b.length, b instanceof Array); // 3, true
console.log('1' in arr); // false
console.log('1' in a); // true (undefined)
console.log('1' in b); // false




但是,如果arr是一个标准数组(没有额外的属性)并且所有的插槽都已填充,则两种方式都会产生相同的结果:

两者都返回一个数组。 [...arr]按定义执行此操作,Object.assign执行此操作,因为它的第一个参数是一个数组,它将返回的对象:mutated,但它的proto不会改变。虽然length不是可枚举属性,Object.assign不会复制它,但第一个参数数组的行为是它将调整其length属性,因为其他属性已分配给它。

两者都是浅色副本。

结论

如果您的数组具有您想要复制的自定义属性,并且最后没有空插槽:请使用Object.assign

如果您的数组没有自定义属性(或者您不关心它们)并且没有空插槽:请使用扩展语法。

如果您的阵列具有您想要复制的自定义属性,并且想要维护空插槽:两种方法都不会同时执行这两项操作。但是使用Object.assign更容易实现:

a = Object.assign([], arr, { length: arr.length });

答案 2 :(得分:1)

要简短,请始终使用...点差构造,而不要在数组上使用Object.assign

Object.assign适用于对象。虽然数组也是对象,但它会对它们产生一定的影响,这实际上是非常有用的。

Object.assign(obj1, obj2)obj2的所有可枚举密钥中获取值,并将其分配给obj1。数组是对象,数组索引实际上是对象键。

[...[1, 2, 3], ...[4, 5]]会产生[1, 2, 3, 4, 5]数组。

Object.assign([1, 2, 3], [4, 5])会生成[4, 5, 3]数组,因为第一个数组中的01索引上的值会被第二个数组中的值覆盖。

如果第一个数组为空,Object.assign([], arr)[...arr]结果相似。但是,[...arr]的正确ES5替代方法是[].concat(arr),而不是Object.assign([], arr)