前言
ES提案中的Rest/Spread Properties
- 剩余部分操作符(...)谷饿,僅用于數(shù)據(jù)解構(gòu)和函數(shù)參數(shù)定義
- 擴(kuò)散操作符(...),僅用于數(shù)組字面量和函數(shù)以及方法調(diào)用的時(shí)候
對(duì)象解構(gòu)中的剩余操作符
可以這么用了
const obj = {foo: 1, bar: 2, baz: 3};
const {foo, ...rest} = obj;
// Same as:
// const foo = 1;
// const rest = {bar: 2, baz: 3};
也可以這么用了
function func({param1, param2, ...rest}) { // rest operator
console.log('All parameters: ',
{param1, param2, ...rest}); // spread operator
return param1 + param2;
}
感覺叼叼的
語(yǔ)法限制
對(duì)象中每一層級(jí)(...)操作符只能用一次专挪,并且只能放在最后
const {...rest, foo} = obj; // SyntaxError
const {foo, ...rest1, ...rest2} = obj; // SyntaxError
你可以這樣用:
const obj = {
foo: {
a: 1,
b: 2,
c: 3,
},
bar: 4,
baz: 5,
};
const {foo: {a, ...rest1}, ...rest2} = obj;
// Same as:
// const a = 1;
// const rest1 = {b: 2, c: 3};
// const rest2 = {bar: 4, baz: 5};
對(duì)象字面量中的擴(kuò)散操作符
在對(duì)象字面量中,可以通過...將A對(duì)象的所有可以枚舉的屬性插入到B對(duì)象中
const A= {foo: 1, bar: 2, baz: 3};
const B = {...obj, qux: 4}
// B: { foo: 1, bar: 2, baz: 3, qux: 4 }
需要注意的是如果屬性名正好相同的話片排,是會(huì)相互覆蓋的寨腔,覆蓋的結(jié)果取決于變量的順序。
const obj = {foo: 1, bar: 2, baz: 3};
{...obj, foo: true}
//{ foo: true, bar: 2, baz: 3 }
{foo: true, ...obj}
//{ foo: 1, bar: 2, baz: 3 }
使用場(chǎng)景及注意事項(xiàng)
克隆對(duì)象
只會(huì)克隆其可枚舉的屬性率寡,不會(huì)克隆其原型指向迫卢,這個(gè)跟Object.assign
很像
如果想克隆其原型,在瀏覽器中可以使用如下的方法
const clone1 = {__proto__: Object.getPrototypeOf(obj), ...obj};
const clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj)), obj);
整體克隆
有的場(chǎng)景下冶共,你需要拷貝對(duì)象的所有屬性:包括writable,enumerable,getters,setters等等乾蛤,這個(gè)時(shí)候Object.assign()和...操作符都沒有無(wú)能為力,可以使用
const clone1 = Object.defineProperties({},
Object.getOwnPropertyDescriptors(obj));
如果還想保留克隆對(duì)象的原型的話比默,可以使用Object.create()
const clone2 = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
淺拷貝
這些克隆操作都是淺拷貝幻捏,需要注意避免可能造成的問題
其他用途
合并對(duì)象
const merged = {...obj1, ...obj2}; const merged = Object.assign({}, obj1, obj2);
附加默認(rèn)值
const DEFAULTS = {foo: 'a', bar: 'b'};
const userData = {foo: 1};
const data = {...DEFAULTS, ...userData};
const data = Object.assign({}, DEFAULTS, userData);
制定個(gè)別鍵的默認(rèn)值
const userData = {foo: 1};
const data = {foo: 'a', bar: 'b', ...userData};
const data = Object.assign({}, {foo:'a', bar:'b'}, userData); // {foo: 1, bar: 'b'}
擴(kuò)散操作符和Object.assign()
的異同
兩種使用Object.assign()
的方式
Object.assign(target, source1, source2);
這個(gè)情況下盆犁,target被改變了
const result = Object.assign({}, source1, source2);
這個(gè)情況下命咐,沒有對(duì)現(xiàn)存的對(duì)象做任何改變
共同點(diǎn)
擴(kuò)散操作符和Object.assign()
都是使用get
操作去讀取value的
擴(kuò)散操作符和Object.assign()
都只能獲取枚舉屬性
不同點(diǎn)
擴(kuò)散操作符定義了屬性,Object.assign()
設(shè)置了屬性
擴(kuò)散操作符在目標(biāo)對(duì)象定義了新的屬性谐岁,Object.assign()
是通過set
操作穿件了屬性醋奠,有兩種結(jié)果:
第一: Object.assign()
會(huì)觸發(fā)setters
Object.defineProperty(Object.prototype, 'foo', {
set(value) {
console.log('SET', value);
},
});
const obj = {foo: 123};
Object.assign({}, obj)
//SET 123
//{}
{ ...obj }
//{ foo: 123 }
第二: 如果目標(biāo)對(duì)象設(shè)置了只讀屬性榛臼,Object.assign()
會(huì)繼承只讀屬性,擴(kuò)散操作符不會(huì)
Object.defineProperty(Object.prototype, 'bar', {
writable: false,
value: 'abc',
});
const tmp = {};
tmp.bar = 123;
// 在嚴(yán)格模式下報(bào)錯(cuò):TypeError: Cannot assign to read only property 'bar'
// 在非嚴(yán)格模式下只是忽略窜司,不報(bào)錯(cuò)