今天看到了你必須收藏的 ES6 語法密糖 - Spread Operator 技巧,這篇文章,收穫不少,同時也想起來
...
也有一些操做對象的用法,總結了一下。html
在 ECMAScript 2018 中 Spread Operator 增長了對對象的支持,使得它的應用更爲普遍,本文重點介紹如何將它與 Object 一塊兒使用以及與 Object.assgin
的區別。es6
能夠經過BABEL,查看示例代碼 babel 編譯後的結果。babel
...
解構賦值除去已經聲明的屬性,剩餘的全部屬性都會賦給 ...
後的屬性名函數
let { x, ...y } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // {y: 2, a: 3, b: 4}
複製代碼
...
刪除屬性值利用 ...
來刪除對象中的某一個屬性post
let { x: deleted, ...y } = { x: 1, y: 2, a: 3, b: 4 };
console.log(y); // {y: 2, a: 3, b: 4}
複製代碼
...
複製對象在 JavaScript 中,有一個常見賦值語法以下ui
var cat = { age: 4 };
var kitten = cat;
kitten.age = 1;
複製代碼
此時, cat
和 kitten
引用同一個對象,若是修改了 kitten
的屬性,相應的 cat
也會發生變化。spa
console.log(kitten.age); // 1
console.log(cat.age); // 1 <-- problem!
複製代碼
使用 Spread Operator 能夠輕鬆地建立一個具備現有對象的全部相同屬性的新對象。prototype
const cat = { age: 4 };
const kitten = { ...cat }; // <-- changed
kitten.age = 1;
console.log(kitten.age); // 1
console.log(cat.age); // 4 <-- fixed!
複製代碼
可是,利用 Spread Operator 去賦值對象,只能完成淺複製,也就是說利用 ...
去複製對象時,並不能遞歸地複製全部層級。rest
const cat = { age: 4, toys: ["mouse", "catnip"] };
const kitten = { ...cat };
// const kitten = Object.assign({}, cat); <-- same result
kitten.toys[1] = "yarn";
console.log(kitten.toys); // ["mouse", "yarn"]
console.log(cat.toys); // ["mouse", "yarn"] <-- problem!
複製代碼
...
擴展對象利用 ...
來拓展對象,就是將新屬性添加到使用 Spread Operator 建立的對象上code
const cat = { legs: 4 };
const dog = {
...cat,
sound: "woof"
};
console.log(cat); // { legs: 4 }
console.log(dog); // { legs: 4, sound: "woof" }
複製代碼
一樣,能夠看到 cat
對象未被更改,但新 dog
對象具備來自 cat
的 legs
屬性以及新 sound
屬性,若是sound
已經存在的話,則會覆蓋。
const cat = { legs: 4, sound: "meow" };
const dog = {
...cat,
sound: "woof"
};
console.log(cat); // { legs: 4, sound: "meow" }
console.log(dog); // { legs: 4, sound: "woof" }
複製代碼
可是,使用 ...
拓展對象時,要注意行順序,也就是
const cat = { legs: 4, sound: "meow" };
const dog = {
sound: "woof",
...cat
};
console.log(cat); // { legs: 4, sound: "meow" }
console.log(dog); // { legs: 4, sound: "meow" }
複製代碼
上述 ...cat
將 sound: "woof"
改寫爲 sound: "meow"
。
...
與 Object.assign
的區別在上述利用 ...
處理對象的過程當中,會發現 ...
有些時候與 Object.assgin
的操做近乎與等價的,那麼他們具體的區別是什麼。
...
和 Object.assign()
總體的用法很是下關係,主要區別在於 Object.assign()
函數會觸發 setters,而 ...
語法則不會,也就是說 ...
是定義了新屬性,而 Object.assign()
則是設置了它們。
Object.assign()
的基本用法改變原有對象
Object.assign(target, source1, source2);
複製代碼
target
已經被修改,source1
以及 source2
會被複制到其中。
建立新的對象
const result = Object.assign({}, source1, source2);
複製代碼
result
是一個新的對象,source1
以及 source2
被複制到其中。
在第二種方法上,...
與 Object.assign()
是很是相似的。接下來,闡述它們之間具體的類似點和不一樣點。
Object.assign
與 ...
的相同點...
和 Object.assign()
都是經過 get
運算符來取值
在將它們寫入目標以前,這兩個操做都會使用 get
操做從源對象讀取相應的屬性值。所以,在此過程當中,getter
將轉換爲正常的數據屬性,具體以下
const original = {
get foo() {
console.log('getter');
return 123;
}
};
複製代碼
original
對象有 getter foo
,而 setter
爲 undeined
Object.getOwnPropertyDescriptor(original, 'foo')
/* log { get: [Function: foo], set: undefined, enumerable: true, configurable: true } */
複製代碼
可是,利用 Object.assgin()
以及 ...
對 original
對象進行克隆時,會發現
const clone1 = {...original};
// 觸發 original 的 getter 會 log "getter"
Object.getOwnPropertyDescriptor(clone1, 'foo');
/* log getter 以及被轉換爲正常的數據屬性 { value: 123, writable: true, enumerable: true, configurable: true } */
const clone2 = Object.assign({}, original);
// 觸發 original 的 getter 會 log "getter"
Object.getOwnPropertyDescriptor(clone2, 'foo')
{
value: 123,
writable: true,
enumerable: true,
configurable: true
}
複製代碼
上述結果代表,在獲得的 clone1
和 clone2
中,foo
只是一個普通的數據屬性(它的屬性描述符具備屬性值和可寫);
...
和 Object.assign
只會處理可枚舉數據
這兩個操做都會忽略全部繼承的屬性和全部不可枚舉的屬性。
const proto = {
inheritedEnumerable: 1,
};
const obj = Object.create(proto, {
ownEnumerable: {
value: 2,
enumerable: true,
},
ownNonEnumerable: {
value: 3,
enumerable: false,
},
});
console.log(obj);
// { ownEnumerable: 2, ownNonEnumerable: 3, __proto__: { inheritedEnumerable: 1 } }
console.log({ ...obj });
// { ownEnumerable: 2 }
console.log(Object.assign({}, obj));
// { ownEnumerable: 2 }
複製代碼
Object.assign
與 ...
的不一樣點它們的不一樣點在於 ...
會定義屬性,而 Object.assign()
會設置它們,也就是說 ...
定義了目標對象中的新屬性,Object.assign()
則是使用 set
操做符進行寫入。
Object.defineProperty(Object.prototype, 'foo', {
set(value) {
console.log('SET', value);
},
});
const obj = {foo: 123};
console.log(Object.assign({}, obj));
// 會觸發 set, log SET 123
// log {}
console.log({ ...obj });
// log { foo: 123 }
複製代碼