《陣列的擴充套件》一章中,已經介紹過擴充套件運算子(……)
const [a, ...b] = [1, 2, 3];
a // 1
b // [2, 3]
es2018 將這個運算子
引入了物件。
解構賦值:
物件的解構賦值用於從乙個物件取值,相當於將目標物件自身的所有可遍歷的(enumberable),但是尚未讀取的屬性,分配到指定的物件上面。
let = ;
x // 1
y // 2
z //
上面**中,變數z
是解構賦值所在的物件。它獲取等號右邊的所有尚未讀取的鍵(a
和b
),將它們連同值一起拷貝過來。
由於解構賦值要求等號右邊是乙個物件,所以如果等號右邊是undefined
或null
,就會報錯,因為它們無法轉為物件。
let = null; // 執行時錯誤
let = undefined; // 執行時錯誤
解構賦值必須是最後乙個引數,否則會報錯。
let = obj; // 句法錯誤
let = obj; // 句法錯誤
上面**中,解構賦值不是最後乙個引數,所以會報錯。
注意,解構賦值的拷貝是淺拷貝,即如果乙個鍵的值是復合型別的值(陣列,物件,函式)、那麼解構賦值拷貝的是這個值的引用,而不是這個值的副本。
let obj = };
let = obj;
obj.a.b = 2;
x.a.b //
上面**中,x
是解構賦值所在的物件,拷貝了物件obj
的a
屬性。a
屬性引用了乙個物件,修改這個物件的值,會影響到解構賦值對它的引用。
另外擴充套件運算子的解構賦值,不能複製繼承自原型物件的屬性。
let o1 = ;
let o2 = ;
o2.__proto__ = o1;
let = o2;
o3 //
o3.a // undefined
上面**中,物件o3
複製了o2
,但是只複製了o2
自身的屬性,沒有複製它的原型物件o1
的屬性。
下面是另乙個例子:
const o = object.create();
o.z = 3;
let } = o;
x // 1
y // undefined
z // 3
上面**中,變數x
是單純的解構賦值,所以可以讀取物件o
繼承的屬性;變數y
和z
是擴充套件運算子的解構賦值,只能讀取物件o
自身的屬性,所以變數z
可以賦值成功,變數y
取不到值。
解構賦值的乙個用處,是擴充套件某個函式的引數,引入其他操作。
function basefunction()
// 使用 x 和 y 引數進行操作
// 其餘引數傳給原始函式
return basefunction(restconfig);
}
上面**中,原始函式basefunction
接受a
和b
作為引數,函式
在basefunction
的基礎上進行了擴充套件,能夠接受多餘的引數,並且保留原始函式的行為。
擴充套件運算子:
物件的擴充套件運算子(……)用於取出引數物件的所有可遍歷屬性,拷貝到當前物件之中。
let z = ;
let n = ;
n //
這等同於使用object.assign
方法。
let aclone = ;
// 等同於
let aclone = object.assign({}, a);
上面的例子只是拷貝了物件例項的屬性,如果想完整轉殖乙個物件,還拷貝物件原型的屬性,可以採用下面的寫法。
// 寫法一
const clone1 = ;
// 寫法二
const clone2 = object.assign(
object.create(object.getprototypeof(obj)),
obj);// 寫法三
const clone3 = object.create(
object.getprototypeof(obj),
object.getownpropertydescriptors(obj)
)
上面**中,寫法一的__proto__
屬性在非瀏覽器的環境不一定部署,因此推薦使用寫法二和寫法三。
擴充套件運算子可以用於合併兩個物件。
let ab = ;
// 等同於
let ab = object.assign({}, a, b);
如果使用者自定義的屬性,放在擴充套件運算子後面,則擴充套件運算子內部的同名屬性會被覆蓋掉。
let awithoverrides = ;
// 等同於
let awithoverrides = };
// 等同於
let x = 1, y = 2, awithoverrides = ;
// 等同於
let awithoverrides = object.assign({}, a, );
上面**中,a
物件的x
屬性和y
屬性,拷貝到新物件後會被覆蓋掉。
這用來修改現有物件部分的屬性就很方便了。
let newversion = ;
上面**中,newversion
物件自定義了name
屬性,其他屬性全部複製自previousversion
物件。
如果把自定義屬性放在擴充套件運算子前面,就變成了設定新物件的預設屬性值。
let awithdefaults = ;
// 等同於
even if property keys don』t clash, because objects record insertion order:
let awithdefaults = object.assign({}, , a);
// 等同於
let awithdefaults = object.assign(, a);
與陣列的擴充套件運算子一樣,物件的擴充套件運算子後面可以跟表示式。
const obj = : {}),
b: 2,
};
如果擴充套件運算子後面是乙個空物件,則沒有任何效果。
, a: 1}
// even if property keys don』t clash, because objects record insertion order:
如果擴充套件運算子的引數是null
或undefined
,這兩個值會被忽略,不會報錯。
let emptyobject = ; // 不報錯
擴充套件運算子的引數物件之中,如果有取值函式get
,這個函式是會執行的。
// 並不會丟擲錯誤,因為 x 屬性只是被定義,但沒執行
let awithxgetter =
};// 會丟擲錯誤,因為 x 屬性被執行了
let runtimeerror =
}};
物件擴充套件運算子( )
當編寫乙個方法時,我們允許它傳入的引數是不確定的。這時候可以使用物件擴充套件運算子來作引數,看乙個簡單的列子 12 3456 78functionjspang arg jspang 1,2,3 這時我們看到控制台輸出了 1,2,3,undefined,這說明是可以傳入多個值,並且就算方法中引用多了也...
物件擴充套件運算子( )與rest運算子
當編寫乙個方法時,我們允許它傳入的引數是不確定的。這時候可以使用物件擴充套件運算子來作引數,看乙個簡單的列子 function xzdemo arg xzdemo 1,2,3 這時我們看到控制台輸出了 1,2,3,undefined,這說明是可以傳入多個值,並且就算方法中引用多了也不會報錯。我們先用...
擴充套件運算子
三個點,主要是用來將陣列幻化為用逗號分隔的引數序列。合併陣列 與解構賦值結合 如果將擴充套件運算子用於陣列賦值,只能放在引數的最後一位,否則會報錯。將字串轉為真正的陣列 可以將類似陣列的物件轉為真正的陣列 map和set結構,generator函式 擴充套件運算子內部呼叫的是資料解構的iterato...