一、两者的定义
1.Object.assign(): Object.assign()方法用于将所有可枚举属性的值从一个过多个源复制到目标对象。它将返回目标对象。
2.展开语法(Spread syntax), 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。
二、两者的用法
1.Object.assign():Object.assign(_target_, ..._sources_)
参数:
target:目标对象
source:源对象
返回值:目标对象target
2.展开语法(Spread syntax)
(1)函数调用: myFunction(...iterableObj);
(2)字面量数组构造或字符串:
[...iterableObj, '4', ...'hello', 6];
(3)构造字面量对象时,进行克隆或者属性拷贝(ECMAScript 2018规范新增特性):
let objClone = { ...obj };
三、两者的异同
共同点
1.两者都是去复制旧的对象进而去创建该对象的一个副本,都可以对源对象中可枚举属性进行复制,可以对symbols属性进行复制。
const obj = {foo: 'bar'};
const clone = { ...obj };
const clone2 = Object.assign({}, obj);
console.log(clone);
console.log(clone2);
输出:
可见,二者都是复制了源对象的可枚举属性去构造了一个对象副本
2.二者都是浅拷贝,即无论是Object Spread运算符还是Object.assign()都是只能复制对象的可枚举属性,而不能复制继承的属性和类的属性,但是它们都会复制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 };
const clone2 = Object.assign({}, obj);
console.log(clone); // { baz: [Function], [Symbol(test)]: 4 }
console.log(clone.constructor.name); // Object
console.log(clone instanceof MyClass); // false
console.log(clone); // { baz: [Function], [Symbol(test)]: 4 }
console.log(clone.constructor.name); // Object
console.log(clone instanceof MyClass); // false
3.如果将null和undefined作为源对象不会报错,但是null和undefined会被忽略
- null作为source
const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};
const t = Object.assign({}, x, y);
console.log(z); //{a: 1, b: 2}
console.log(t); //{a: 1, b: 2}
- undefinded作为source
const x = {a: 1, b: 2};
const clone = Object.assign(undefined, x);
const clone2 = {undefined, ...x};
console.log(clone); //TypeError: Cannot convert undefined or null to object
console.log(clone2); //TypeError: Cannot convert undefined or null to object
5.如果null和undefined作为源对象中的属性值,则他们不会被忽略。
//null和undefined作为source里面的property
const x = {a: null, b: 1, c: 2};
const y = {a: undefined, b: 1, c: 2};
console.log(Object.assign({}, x)); //{ a: null, b: 1, c: 2 }
console.log(Object.assign({}, y)); //{ a: undefined, b: 1, c: 2 }
不同点
1.对于上面的例子,Object.assign()函数基本上可以和Object spread操作符互换,object spread spec明确指出
{... obj}等同于Object.assign({},obj)。
那么你为什么要使用其中一个呢?一个关键的区别是 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(),你必须确保始终将空对象{}作为第一个参数传递。
2.下面是一个使用Object.assign()和in-place赋值的基准测试(引用自:[[译] Object.assign 和 Object Spread 之争, 用谁?](https://juejin.im/post/5c5d8d...)
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
四、总结
总的来说,Object spread运算符和Object.assign()的功能类似,但是Object spread运算符在语法上更加简洁,并且比Object.assign()提供了性能优势。 如果你运行的是Node.js 8或更高版本,请尝试使用这些新运算符,使代码更简洁。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。