假设我有一个options
变量,并且想要设置一些默认值。
这两种选择的优点/缺点是什么?
使用对象传播
options = {...optionsDefault, ...options};
或使用Object.assign
options = Object.assign({}, optionsDefault, options);
这就是让我感到奇怪的承诺。
假设我有一个options
变量,并且想要设置一些默认值。
这两种选择的优点/缺点是什么?
使用对象传播
options = {...optionsDefault, ...options};
或使用Object.assign
options = Object.assign({}, optionsDefault, options);
这就是让我感到奇怪的承诺。
Answers:
这并不一定是详尽无遗的。
options = {...optionsDefault, ...options};
如果编写代码以在没有本机支持的环境中执行,则可以仅编译此语法(与使用polyfill相对)。(例如,使用Babel。)
不太冗长。
最初编写此答案时,这只是一个建议,而不是标准化的。在使用投标时,请考虑一下如果现在使用它编写代码会做什么,并且在朝着标准化的方向发展时,它不会变得标准化或更改。此后已在ES2018中标准化。
从字面上看,不是动态的。
Object.assign()
options = Object.assign({}, optionsDefault, options);
标准化。
动态。例:
var sources = [{a: "A"}, {b: "B"}, {c: "C"}];
options = Object.assign.apply(Object, [{}].concat(sources));
// or
options = Object.assign({}, ...sources);
这就是让我感到奇怪的承诺。
这与您的要求没有直接关系。该代码未使用Object.assign()
,它正在使用object-assign
执行相同操作的用户代码()。他们似乎正在使用Babel编译该代码(并将其与Webpack捆绑在一起),这就是我所说的:您可以编译的语法。他们显然更喜欢将其包含object-assign
在其构建中作为依赖项。
Object.assign()
。或者,您可以手动遍历对象的数组,并手动将它们自己的道具手动分配给目标,并使它更加冗长:P
作为参考,对象的休息/传播在ECMAScript 2018中最终确定为阶段4。可以在此处找到建议。
大多数情况下,对象重置和散布都以相同的方式进行,主要区别在于散布定义属性,而Object.assign()设置属性。这意味着Object.assign()触发设置器。
值得记住的是,除此之外,对象休息/传播1:1映射到Object.assign()并以不同的方式作用于数组(可迭代)传播。例如,在扩展数组时,将扩展空值。但是,使用对象扩展时,空值会默默地扩展为零。
数组(可迭代)传播示例
const x = [1, 2, null , 3];
const y = [...x, 4, 5];
const z = null;
console.log(y); // [1, 2, null, 3, 4, 5];
console.log([...z]); // TypeError
对象传播示例
const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};
console.log(z); //{a: 1, b: 2}
这与Object.assign()的工作方式一致,两者均无提示地无提示地排除了null值。
const x = null;
const y = {a: 1, b: 2};
const z = Object.assign({}, x, y);
console.log(z); //{a: 1, b: 2}
Object.assign
将使用二传手。Object.assign({set a(v){this.b=v}, b:2}, {a:4}); // {b: 4}
主场迎战{...{set a(v){this.b=v}, b:2}, ...{a:4}}; // {a: 4, b: 2}
const x = {c: null};
。在这种情况下,对于AFAIK,我们将看到类似于数组的行为://{a: 1, b: 2, c: null}
。
我认为,散布运算符与Object.assign
当前答案中似乎没有提到的一个大区别是,散布运算符不会将源对象的原型复制到目标对象。如果要向对象添加属性,并且不想更改对象的实例,则必须使用Object.assign
。下面的示例应证明这一点:
const error = new Error();
error instanceof Error // true
const errorExtendedUsingSpread = {
...error,
...{
someValue: true
}
};
errorExtendedUsingSpread instanceof Error; // false
const errorExtendedUsingAssign = Object.assign(error, {
someValue: true
});
errorExtendedUsingAssign instanceof Error; // true
errorExtendedUsingAssign === error
,,但是errorExtendedUsingSpread
是一个新对象(并且未复制原型)。
let target = Object.create(source); Object.assign(target, source);
正如其他人提到的那样,在撰写本文时,它Object.assign()
需要一个...
polyfill,而对象散布则需要一些转堆(也许还有一个polyfill)才能起作用。
考虑以下代码:
// Babel wont touch this really, it will simply fail if Object.assign() is not supported in browser.
const objAss = { message: 'Hello you!' };
const newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);
// Babel will transpile with use to a helper function that first attempts to use Object.assign() and then falls back.
const objSpread = { message: 'Hello you!' };
const newObjSpread = {...objSpread, dev: true };
console.log(newObjSpread);
这些都产生相同的输出。
这是Babel到ES5的输出:
var objAss = { message: 'Hello you!' };
var newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var objSpread = { message: 'Hello you!' };
var newObjSpread = _extends({}, objSpread, { dev: true });
console.log(newObjSpread);
到目前为止,这是我的理解。Object.assign()
实际上是标准化的,因为...
还没有对象传播。唯一的问题是浏览器支持前者,将来也支持后者。
希望这可以帮助。
{}
应该可以解决不一致问题。
对象散布运算符(...)在浏览器中不起作用,因为它还不是任何ES规范的一部分,只是一个建议。唯一的选择是用Babel(或类似的东西)编译它。
如您所见,它只是Object.assign({})上的语法糖。
据我所知,这些是重要的区别。
...
对于对象没有标准化...
保护您免于意外改变对象...
没有它会在浏览器中填充Object.assign...
需要更少的代码来表达相同的想法Object.assign
,因为传播操作符将始终为您提供一个新对象。
我想通过工具总结“扩展对象合并” ES功能在浏览器和生态系统中的状态。
var x = { a: 1, b: 2 };
var y = { c: 3, d: 4, a: 5 };
var z = {...x, ...y};
console.log(z); // { a: 5, b: 2, c: 3, d: 4 }
再次:在撰写本文时,该示例在Chrome(60 +),Firefox Developer Edition(Firefox 60的预览版)和Node(8.7+)中无需转换即可工作。
我写这2.5 年在提出原始问题后2.。但是我也有同样的问题,这就是Google发送给我的地方。我是SO改善长尾巴任务的奴隶。
由于这是“数组传播”语法的扩展,因此我发现很难用Google搜索,也很难在兼容性表中找到。我能找到的最接近的是Kangax“ property spread”,但是该测试在同一表达式中没有两个价差(不是合并)。此外,投标/草稿/浏览器状态页面中的名称均使用“属性传播”,但在我看来,这是社区在提议使用传播语法进行“对象合并”之后到达的“第一主体”。(这可能会解释为什么Google这么难的原因。)因此,我在这里记录我的发现,以便其他人可以查看,更新和编译有关此特定功能的链接。我希望它能流行起来。请帮助在规范和浏览器中传播有关它着陆的消息。
最后,我会将此信息添加为评论,但是如果不破坏作者的初衷,就无法对其进行编辑。具体来说,我不能编辑@ChillyPenguin的评论,除非它失去他纠正@RichardSchulte的意图。但是几年后,理查德证明是正确的(我认为)。因此,我改写了这个答案,希望它最终会在旧的答案上引起关注(可能要花几年时间,但这毕竟是长尾效应的全部内容)。
注意:传播不只是Object.assign周围的语法糖。他们在幕后的运作方式大不相同。
Object.assign将设置器应用于新对象,Spread则不然。另外,对象必须是可迭代的。
复制 如果您现在需要该对象的值,并且不希望该值反映该对象的其他所有者所做的任何更改,请使用此值。
使用它创建对象的浅表副本的最佳做法是始终将不可变属性设置为复制-因为可变版本可以传递给不可变属性,所以复制将确保您将始终处理不可变对象
分配 分配与复制有点相反。Assign将生成一个setter,该setter会将值直接分配给实例变量,而不是复制或保留它。调用assign属性的getter时,它将返回对实际数据的引用。
其他答案很旧,无法获得很好的答案。
下面的示例是针对对象文字的,它可以帮助它们如何相互补充,以及如何不能相互补充(因此有所不同):
var obj1 = { a: 1, b: { b1: 1, b2: 'b2value', b3: 'b3value' } };
// overwrite parts of b key
var obj2 = {
b: {
...obj1.b,
b1: 2
}
};
var res2 = Object.assign({}, obj1, obj2); // b2,b3 keys still exist
document.write('res2: ', JSON.stringify (res2), '<br>');
// Output:
// res2: {"a":1,"b":{"b1":2,"b2":"b2value","b3":"b3value"}} // NOTE: b2,b3 still exists
// overwrite whole of b key
var obj3 = {
b: {
b1: 2
}
};
var res3 = Object.assign({}, obj1, obj3); // b2,b3 keys are lost
document.write('res3: ', JSON.stringify (res3), '<br>');
// Output:
// res3: {"a":1,"b":{"b1":2}} // NOTE: b2,b3 values are lost
这里还有一些关于数组和对象的小例子:https :
//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
现在这是ES6的一部分,因此已经标准化,并且还记录在MDN上: https //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
它非常方便使用,并且与对象分解一起意义重大。
上面列出的一个剩余优点是Object.assign()的动态功能,但是,这与将数组扩展到文字对象内部一样容易。在编译的babel输出中,它完全使用Object.assign()演示的内容
因此正确的答案是使用对象散布,因为它现在已经标准化,被广泛使用(请参阅react,redux等),易于使用并且具有Object.assign()的所有功能。
当您必须使用Object.assign时,我想添加一个简单的示例。
class SomeClass {
constructor() {
this.someValue = 'some value';
}
someMethod() {
console.log('some action');
}
}
const objectAssign = Object.assign(new SomeClass(), {});
objectAssign.someValue; // ok
objectAssign.someMethod(); // ok
const spread = {...new SomeClass()};
spread.someValue; // ok
spread.someMethod(); // there is no methods of SomeClass!
使用JavaScript时不清楚。但是如果您想创建某个类的实例,使用TypeScript会更容易
const spread: SomeClass = {...new SomeClass()} // Error