![](/img/trans.png)
[英]Object mutates in Redux despite Object.assign and Spread syntax
[英]Difference between Object.assign and object spread (using […] syntax)?
我在这里有一些代码,我想知道这是同一件事还是不同。 我很确定这两个都应该是相同的,但是我不确定自己是否做对了。
let zoneComment = updatedMap[action.comment.zone]
? [...updatedMap[action.comment.zone]] : [];
let zoneComment = updatedMap[action.comment.zone]
? Object.assign([], updatedMap[action.comment.zone]) : [];
如果这些相同,那我应该使用哪个呢? 我想使用最佳做法,因此,如果您的意见更好,请声明。
在您的特定情况下,他们是不一样的。
原因是您拥有一个数组,而不是一个对象。
在数组上执行...
将散布数组中的所有元素(但不包括属性)
做Object.assign
需要一个对象,因此它将数组视为对象并将所有可枚举的自身属性复制到其中,而不仅仅是元素:
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之类的工具进行预处理(编译)步骤。
您的问题真的可以归结为:
当arr
是数组时Object.assign([], arr)
[...arr]
和Object.assign([], arr)
提供相同的结果?
答案是:通常是,但是:
如果arr
是一个最后一个槽没有值的稀疏数组,则两种情况下结果的length
属性将不同:spread语法将为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
则执行此操作,因为它的第一个参数是一个数组,并且它将返回该对象:突变,但它的原型不会改变。 尽管length
不是可枚举的属性,并且Object.assign
不会复制它,但是第一个参数数组的行为是它将在为其分配其他属性时适应其length
属性。
两者均采用浅拷贝。
如果您的数组具有自定义属性,则希望复制该数组,并且该数组的末尾没有空插槽:使用Object.assign
。
如果您的数组没有自定义属性(或者您不关心它们)并且没有空插槽,请使用传播语法。
如果您的数组具有要复制的自定义属性,并且要保留空的插槽,则这两种方法都不会做到。 但是使用Object.assign
可以更轻松地完成:
a = Object.assign([], arr, { length: arr.length });
为了简短Object.assign
,请始终使用...
传播构造,切勿在数组上使用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]
数组,因为第一个数组中0
和1
索引上的值会被第二个数组中的值覆盖。
在第一个数组为空的情况下, Object.assign([], arr)
和[...arr]
结果相似。 但是, [...arr]
的合适ES5替代方法是[].concat(arr)
而不是Object.assign([], arr)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.