1. 程式人生 > >你要知道的 - Spread Operator for objects 技巧

你要知道的 - Spread Operator for objects 技巧

今天看到了你必須收藏的 ES6 語法密糖 - Spread Operator 技巧,這篇文章,收穫很多,同時也想起來 ... 也有一些操作物件的用法,總結了一下。

在 ECMAScript 2018 中 Spread Operator 增加了對物件的支援,使得它的應用更為廣泛,本文重點介紹如何將它與 Object 一起使用以及與 Object.assgin 的區別。

可以通過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} 複製程式碼
... 刪除屬性值

利用 ... 來刪除物件中的某一個屬性

let { x: deleted, ...y } = { x: 1, y: 2, a: 3, b: 4 };
console.log(y); // {y: 2, a: 3, b: 4}
複製程式碼
... 複製物件

在 JavaScript 中,有一個常見賦值語法如下

var cat = { age: 4 };
var kitten = cat;
kitten.age = 1;
複製程式碼

此時, catkitten 引用同一個物件,如果修改了 kitten 的屬性,相應的 cat 也會發生變化。

console.log(kitten.age); // 1
console.log(cat.age); // 1 <-- problem!
複製程式碼

使用 Spread Operator 可以輕鬆地建立一個具有現有物件的所有相同屬性的新物件。

const cat = { age: 4 };
const kitten = { ...cat }; // <-- changed
kitten.age = 1;

console.log(kitten.age); // 1
console
.log(cat.age); // 4 <-- fixed! 複製程式碼

但是,利用 Spread Operator 去賦值物件,只能完成淺複製,也就是說利用 ... 去複製物件時,並不能遞迴地複製所有層級。

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 建立的物件上

const cat = { legs: 4 };
const dog = {
    ...cat,
    sound: "woof"
};
console.log(cat); // { legs: 4 }
console.log(dog); // { legs: 4, sound: "woof" }
複製程式碼

同樣,可以看到 cat 物件未被更改,但新 dog 物件具有來自 catlegs 屬性以及新 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" }
複製程式碼

上述 ...catsound: "woof" 改寫為 sound: "meow"

...Object.assign 的區別

在上述利用 ... 處理物件的過程中,會發現 ... 有些時候與 Object.assgin 的操作近乎與等價的,那麼他們具體的區別是什麼。

Object.assign() 函式會觸發 setters,而展開語法則不會*,具體的程式碼如下

const cat = {
  set feature(value) {
    console.log('set', value)
    this.features.push(value)
  },
  features: []
};

cat.feature = 'cute'; // log set cute

const dog = {
  feature: 'kind'
};

const monster = Object.assign(cat, dog); 
// 由於觸發setters,則 log kind
const anotherMonster = { ...cat, ...dog };
// 無log
複製程式碼

上述程式碼中 monster

anotherMonster

顯然 Spread Operator 沒有對 setters 做處理,只是作為普通屬性進行賦值。

參考