假设我有一个选项变量我想设置一个默认值。
这两种选择的优点/缺点是什么?
使用对象扩展
options = {...optionsDefault, ...options};
或者使用Object.assign
options = Object.assign({}, optionsDefault, options);
这是让我疑惑的承诺。
假设我有一个选项变量我想设置一个默认值。
这两种选择的优点/缺点是什么?
使用对象扩展
options = {...optionsDefault, ...options};
或者使用Object.assign
options = Object.assign({}, optionsDefault, options);
这是让我疑惑的承诺。
当前回答
我想总结一下“扩展对象合并”ES特性在浏览器和工具生态系统中的状态。
Spec
https://github.com/tc39/proposal-object-rest-spread 这个语言特性是第4阶段的提案,这意味着它已经被合并到ES语言规范中,但还没有被广泛实现。
浏览器:Chrome, SF, Firefox(60版本,IIUC)
浏览器支持Chrome 60中附带的“传播属性”,包括这个场景。 在当前的Firefox(59)中不支持此场景,但在我的Firefox开发者版中可以。所以我相信它会在Firefox 60中发布。 Safari:未测试,但Kangax说它可以在桌面Safari 11.1中运行,但不适用于SF 11 iOS Safari:未测试,但Kangax说它可以在iOS 11.3运行,但不能在iOS 11运行 还没有在Edge中
工具:Node 8.7, TS 2.1
NodeJS从8.7开始支持(通过Kangax)。9.8在本地测试时确认。 TypeScript从2.1开始支持它,目前是2.8
链接
Kangax“财产蔓延” https://davidwalsh.name/merge-objects
代码示例(兼作兼容性测试)
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+)中工作。
为什么答案?
我是在最初的问题提出两年半后写这篇文章的。但我也有同样的问题,谷歌让我来这里。我是SO改善长尾理论使命的奴隶。
Since this is an expansion of "array spread" syntax I found it very hard to google, and difficult to find in compatibility tables. The closest I could find is Kangax "property spread", but that test doesn't have two spreads in the same expression (not a merge). Also, the name in the proposals/drafts/browser status pages all use "property spread", but it looks to me like that was a "first principal" the community arrived at after the proposals to use spread syntax for "object merge". (Which might explain why it is so hard to google.) So I document my finding here so others can view, update, and compile links about this specific feature. I hope it catches on. Please help spread the news of it landing in the spec and in browsers.
最后,我本可以将这些信息作为评论添加进来,但我无法在不破坏作者原始意图的情况下编辑它们。具体来说,我无法编辑@ chillpenguin的评论,否则它就会失去纠正@RichardSchulte的意图。但多年后,理查德(在我看来)证明是对的。所以我写了这个答案,希望它最终能取代旧的答案(可能需要几年时间,但毕竟这就是长尾效应的意义所在)。
其他回答
对象扩展操作符(…)在浏览器中不起作用,因为它还不是任何ES规范的一部分,只是一个建议。唯一的选择是用Babel(或类似的东西)编译它。
正如您所看到的,它只是Object.assign({})上的语法糖。
在我看来,这些是重要的区别。
对象。赋值在大多数浏览器中都有效(不需要编译) ... For对象不是标准化的 ... 防止您意外地改变对象 ... 将填充对象。在没有它的浏览器中赋值 ... 需要更少的代码来表达相同的思想
太多的错误答案……
我搜索了一下,发现了很多关于这方面的错误信息。
总结
既不……扩散也不反对。赋值更快。视情况而定。 对象。如果不考虑副作用/对象突变,Assign几乎总是更快。 除了性能之外,使用这两种方法通常都没有优点或缺点,直到遇到极限情况,例如复制包含getter /setter的对象或只读属性。点击这里阅读更多。
性能
是否对象。Assign或…传播速度更快,这取决于你想要组合的东西,以及你正在使用的运行时(实现和优化不时发生)。对于小的对象,这无关紧要。
对于较大的对象,请使用Object。Assign通常更好。特别是在不需要关心副作用的情况下,只需向第一个对象添加属性就可以节省时间,而不是复制两个对象并创建一个全新的对象。看到的:
async function retrieveAndCombine() {
const bigPayload = await retrieveData()
const smallPayload = await retrieveData2()
// only the properties of smallPayload is iterated through
// whereas bigPayload is mutated.
return Object.assign(bigPayload, smallPayload)
}
如果有副作用的话
在副作用很重要的情况下,例如将一个对象与另一个对象组合作为参数传入。
在下面的例子中,bigPayload将被改变,如果retrieveAndCombine之外的其他函数/对象依赖于bigPayload,这是一个坏主意。在这种情况下,可以交换传递给Object的参数。赋值,或者直接使用{}作为第一个参数来创建一个新对象:
async function retrieveAndCombine(bigPayload) {
const smallPayload = await retrieveData2()
// this is slightly more efficient
return Object.assign(smallPayload, bigPayload)
// this is still okay assuming `smallPayload` only has a few properties
return Object.assign({}, smallPayload, bigPayload)
}
Test
试试下面的代码片段。注意:运行需要一段时间。
const rand = () => (Math.random() + 1).toString(36).substring(7) function combineBigObjects() { console.log('Please wait...creating the test objects...') const obj = {} const obj2 = {} for (let i = 0; i < 100000; i++) { const key = rand() obj[rand()] = { [rand()]: rand(), [rand()]: rand(), } obj2[rand()] = { [rand()]: rand(), [rand()]: rand(), } } console.log('Combine big objects using spread:') console.time() const result1 = { ...obj, ...obj2, } console.timeEnd() console.log('Combine big objects using assign:') console.time() Object.assign({}, obj, obj2) console.timeEnd() console.log('Combine big objects using assign, but mutates first obj:') console.time() Object.assign(obj, obj2) console.timeEnd() } combineBigObjects() function combineSmallObjects() { const firstObject = () => ({ [rand()]: rand() }) const secondObject = () => ({ [rand()]: rand() }) console.log('Combine small objects using spread:') console.time() for (let i = 0; i < 500000; i++) { const finalObject = { ...firstObject(), ...secondObject(), } } console.timeEnd() console.log('Combine small objects using assign:') console.time() for (let i = 0; i < 500000; i++) { const finalObject = Object.assign({}, firstObject(), secondObject()) } console.timeEnd() console.log('Combine small objects using assign, but mutates first obj:') console.time() for (let i = 0; i < 500000; i++) { const finalObject = Object.assign(firstObject(), secondObject()) } console.timeEnd() } combineSmallObjects()
(1)创建对象的浅副本和(2)将多个对象合并为单个对象的方法在2014年至2018年之间有了很大的发展。
下面概述的方法在不同时期变得可用并广泛使用。这个答案提供了一些历史视角,但并不详尽。
如果没有库或现代语法的帮助,您将使用for-in循环,例如。 var mergedOptions = {} for (var键在defaultOptions) { mergedOptions[key] = defaultOptions[key] } 对于(var键在选项中){ mergedOptions[key] = options[key] } options = mergedOptions
2006
jQuery 1.0有jQuery.extend(): 选项= $。extend({}, defaultOptions, options)
⋮
2010
下划线。js 1.0有_.extend() 选项= _。extend({}, defaultOptions, options)
⋮
2014
2ality发布了一篇关于Object.assign()加入ES2015的文章 对象分配发布到npm。 var objectAssign = require('object-assign') options = objectAssign({}, defaultOptions, options) ES2016提出的对象Rest/扩展属性语法。
2015
对象。Chrome (45), Firefox(34)和Node.js(4)都支持assign。不过,旧的运行时需要Polyfill。 options =对象。assign({}, defaultOptions, options) 对象Rest/Spread Properties提案进入第二阶段。
2016
对象Rest/扩展属性语法没有被包含在ES2016中,但是提案已经到了第三阶段。
2017
对象Rest/Spread属性语法没有包含在ES2017中,但在Chrome (60), Firefox(55)和Node.js(8.3)中可用。不过,旧的运行时需要一些编译。 选项={…defaultOptions,…选择}
2018
对象Rest/Spread Properties提案达到了第4阶段,语法被包含在ES2018标准中。
我们将创建一个名为identity的函数,它只返回我们给它的任何参数。
identity = (arg) => arg
和一个简单的数组。
arr = [1, 2, 3]
如果用arr求恒等函数,我们知道会发生什么
当你必须使用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