擴(kuò)展運(yùn)算符

對(duì)象的擴(kuò)展運(yùn)算符(...)用于取出參數(shù)對(duì)象的所有可遍歷屬性,拷貝到當(dāng)前對(duì)象之中。

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

由于數(shù)組是特殊的對(duì)象,所以對(duì)象的擴(kuò)展運(yùn)算符也可以用于數(shù)組。

let foo = { ...['a', 'b', 'c'] };
foo
// {0: "a", 1: "b", 2: "c"}

如果擴(kuò)展運(yùn)算符后面是一個(gè)空對(duì)象,則沒有任何效果。

{...{}, a: 1}
// { a: 1 }

如果擴(kuò)展運(yùn)算符后面不是對(duì)象,則會(huì)自動(dòng)將其轉(zhuǎn)為對(duì)象。

// 等同于 {...Object(1)}
{...1} // {}

上面代碼中,擴(kuò)展運(yùn)算符后面是整數(shù)1,會(huì)自動(dòng)轉(zhuǎn)為數(shù)值的包裝對(duì)象Number{1}。由于該對(duì)象沒有自身屬性,所以返回一個(gè)空對(duì)象。

下面的例子都是類似的道理。

// 等同于 {...Object(true)}
{...true} // {}

// 等同于 {...Object(undefined)}
{...undefined} // {}

// 等同于 {...Object(null)}
{...null} // {}

但是,如果擴(kuò)展運(yùn)算符后面是字符串,它會(huì)自動(dòng)轉(zhuǎn)成一個(gè)類似數(shù)組的對(duì)象,因此返回的不是空對(duì)象。

{...'hello'}
// {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}

對(duì)象的擴(kuò)展運(yùn)算符等同于使用Object.assign()方法。

let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);

上面的例子只是拷貝了對(duì)象實(shí)例的屬性,如果想完整克隆一個(gè)對(duì)象,還拷貝對(duì)象原型的屬性,可以采用下面的寫法。

// 寫法一
const clone1 = {
  __proto__: Object.getPrototypeOf(obj),
  ...obj
};

// 寫法二
const clone2 = Object.assign(
  Object.create(Object.getPrototypeOf(obj)),
  obj
);

// 寫法三
const clone3 = Object.create(
  Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj)
)

上面代碼中,寫法一的proto屬性在非瀏覽器的環(huán)境不一定部署,因此推薦使用寫法二和寫法三。

擴(kuò)展運(yùn)算符可以用于合并兩個(gè)對(duì)象。

let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);

如果用戶自定義的屬性,放在擴(kuò)展運(yùn)算符后面,則擴(kuò)展運(yùn)算符內(nèi)部的同名屬性會(huì)被覆蓋掉。

let aWithOverrides = { ...a, x: 1, y: 2 };
// 等同于
let aWithOverrides = { ...a, ...{ x: 1, y: 2 } };
// 等同于
let x = 1, y = 2, aWithOverrides = { ...a, x, y };
// 等同于
let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });

上面代碼中,a對(duì)象的x屬性和y屬性,拷貝到新對(duì)象后會(huì)被覆蓋掉。

這用來修改現(xiàn)有對(duì)象部分的屬性就很方便了。

let newVersion = {
  ...previousVersion,
  name: 'New Name' // Override the name property
};

上面代碼中,newVersion對(duì)象自定義了name屬性,其他屬性全部復(fù)制自previousVersion對(duì)象。

如果把自定義屬性放在擴(kuò)展運(yùn)算符前面,就變成了設(shè)置新對(duì)象的默認(rèn)屬性值。

let aWithDefaults = { x: 1, y: 2, ...a };
// 等同于
let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a);
// 等同于
let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);

與數(shù)組的擴(kuò)展運(yùn)算符一樣,對(duì)象的擴(kuò)展運(yùn)算符后面可以跟表達(dá)式。

const obj = {
  ...(x > 1 ? {a: 1} : {}),
  b: 2,
};

擴(kuò)展運(yùn)算符的參數(shù)對(duì)象之中,如果有取值函數(shù)get,這個(gè)函數(shù)是會(huì)執(zhí)行的。

// 并不會(huì)拋出錯(cuò)誤,因?yàn)?x 屬性只是被定義,但沒執(zhí)行
let aWithXGetter = {
  ...a,
  get x() {
    throw new Error('not throw yet');
  }
};

// 會(huì)拋出錯(cuò)誤,因?yàn)?x 屬性被執(zhí)行了
let runtimeError = {
  ...a,
  ...{
    get x() {
      throw new Error('throw now');
    }
  }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容