[译] Object.assign 和 Object Spread 之争, 用谁?
栏目: JavaScript · 发布时间: 5年前
内容简介:原文链接在 2018 年Object Spread 也可以叫做对象展开符,下文都以 Object Spread 来进行描述。
原文链接 thecodebarbarian.com/object-assi…
在 2018 年 Object Rest/Spread Proposal 达到了stage 4,这意味着在未来它会将入到 ECMAScript 标准中。它也被加入到Node LTS. Node.js 8 以后的版本你可以使用它,所以你可以放心地开始使用它。
Object Spread 也可以叫做对象展开符,下文都以 Object Spread 来进行描述。
$ node -v v8.9.4 $ node > const obj = { foo: 1, bar: 1 }; undefined > ({ ...obj, baz: 1 }); { foo: 1, bar: 1, baz: 1 } 复制代码
Object Spread 和 Object.assign 在功能上很相似。你应该使用哪一个? 事实证明,答案比你想象的要微妙许多。
Object Spread 概论
Object Spread 运算符的基本思想是使用现有对象的自身属性来创建新的普通对象。 所以 {...obj}
创建一个和 obj
具有相同属性的对象。 对于 普通的旧 JavaScript 对象
,你实际上是在创建一个 obj
副本。
const obj = { foo: 'bar' }; const clone = { ...obj }; // `{ foo: 'bar' }` obj.foo = 'baz'; clone.foo; // 'bar' 复制代码
与object .assign()类似,Object spread 操作符不复制继承的属性或类的属性。但是它会复制 ES6 的symbols 属性。
class BaseClass { foo() { return 1; } } class MyClass extends BaseClass { bar() { return 2; } } const obj = new MyClass(); obj.baz = function() { return 3; }; obj[Symbol.for('test')] = 4; // Does _not_ copy any properties from `MyClass` or `BaseClass` const clone = { ...obj }; console.log(clone); // { baz: [Function], [Symbol(test)]: 4 } console.log(clone.constructor.name); // Object console.log(clone instanceof MyClass); // false 复制代码
还可以使用 Object spread 操作符混合其他属性。
顺序问题: Object spread 操作符将覆盖在它之前定义的属性。
const obj = { a: 'a', b: 'b', c: 'c' }; { a: 1, b: null, c: void 0, ...obj }; // { a: 'a', b: 'b', c: 'c' } { a: 1, b: null, ...obj, c: void 0 }; // { a: 'a', b: 'b', c: undefined } { a: 1, ...obj, b: null, c: void 0 }; // { a: 'a', b: null, c: undefined } { ...obj, a: 1, b: null, c: void 0 }; // { a: 1, b: null, c: undefined } 复制代码
和 Object.assign() 的区别
对于上面的例子, Object.assign()
函数基本上可以与 Object spread 操作符互换。事实上, object spread spec
明确指出 {... obj}
等同于 Object.assign({},obj)
。
const obj = { a: 'a', b: 'b', c: 'c' }; Object.assign({ a: 1, b: null, c: void 0 }, obj); // { a: 'a', b: 'b', c: 'c' } Object.assign({ a: 1, b: null }, obj, { c: void 0 }); // { a: 'a', b: 'b', c: undefined } Object.assign({ a: 1 }, obj, { b: null, c: void 0 }); // { a: 'a', b: null, c: undefined } Object.assign({}, obj, { a: 1, b: null, c: void 0 }); // { a: 1, b: null, c: undefined } 复制代码
那么你为什么要使用其中一个呢?一个关键的区别是 Object spread 操作符总是给你一个POJO(Plain Ordinary JavaScript Object)。而 Object.assign()
函数却修改其第一个传入对象 obj
:
class MyClass { set val(v) { console.log('Setter called', v); return v; } } const obj = new MyClass(); Object.assign(obj, { val: 42 }); // Prints "Setter called 42" 复制代码
换句话说, Object.assign()
修改了一个对象,因此它可以触发ES6 setter。如果你更喜欢使用immutable技术,那么 Object spread 操作符就是你更好的选择。使用 Object.assign()
,你必须确保始终将空对象 {}
作为第一个参数传递。
性能怎么样? 这是一些简单的基准测试。如果将空对象作为第一个参数传递给 Object.assign()
,看起来 Object spread 会更快,但除此之外它们是可互换的。
下面是一个使用 Object.assign()
和in-place赋值的基准测试:
const Benchmark = require('benchmark'); const suite = new Benchmark.Suite; const obj = { foo: 1, bar: 2 }; suite. add('Object spread', function() { ({ baz: 3, ...obj }); }). add('Object.assign()', function() { Object.assign({ baz: 3 }, obj); }). on('cycle', function(event) { console.log(String(event.target)); }). on('complete', function() { console.log('Fastest is ' + this.filter('fastest').map('name')); }). run({ 'async': true }); 复制代码
在这种情况下,两者是相似的:
Object spread x 3,170,111 ops/sec +-1.50% (90 runs sampled) Object.assign() x 3,290,165 ops/sec +-1.86% (88 runs sampled) Fastest is Object.assign() 复制代码
但是,一旦向 Object.assign()
输入一个空对象参数,对象扩展运算符就会更快
suite. add('Object spread', function() { ({ baz: 3, ...obj }); }). add('Object.assign()', function() { Object.assign({}, obj, { baz: 3 }); }) 复制代码
这是输出:
Object spread x 3,065,831 ops/sec +-2.12% (85 runs sampled) Object.assign() x 2,461,926 ops/sec +-1.52% (88 runs sampled) Fastest is Object spread 复制代码
ESLint 配置
默认情况下,ESLint在解析层面 禁止对象rest / spread运算符 你需要在.eslintrc.yml中将parserOptions.ecmaVersion选项设置为至少9,否则你将得到一个解析错误。
parserOptions: # Otherwise object spread causes 'Parsing error: Unexpected token ..' ecmaVersion: 9 复制代码
ESLint添加了一个 新的规则
prefer-object-spread,它会强制你使用 Object spread 操作符 而不是 Object.assign()
。 要启用此规则,请使用:
parserOptions: ecmaVersion: 9 rules: prefer-object-spread: error 复制代码
现在,如果您使用 object .assign()
而不是Object spread, ESLint将报告一个错误。
Use an object spread instead of `Object.assign` eg: `{ ...foo }` prefer-object-spread 复制代码
最后
Object rest / spread运算符在语法更加简洁,并且比 Object.assign()
提供了性能优势。 如果你运行的是Node.js 8或更高版本,请尝试使用这些新运算符,使代码更简洁。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript征途
朱印宏 / 电子工业出版社 / 2009-9 / 89.00元
《JavaScript征途》是一本学习JavaScript语言的权威书籍,在遵循语言学习的特殊规律基础上精心选材,力争做到统筹、有序,在结构上体现系统性和完整性。同时还重点挖掘JavaScript基于对象的开发精髓及函数式编程两个技术核心。《JavaScript征途》内容全面,由浅入深,包括6篇21章,主要内容包括:JavaScript语言的基本特性,开发简单的JavaScript程序,JavaS......一起来看看 《JavaScript征途》 这本书的介绍吧!