擴(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 }
對(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)境不一定部署镜硕,因此推薦使用寫法二和寫法三运翼。
數(shù)組的解構(gòu)賦值
let [a, b, c] = [1, 2, 3];
對(duì)號(hào)入座。本質(zhì)上兴枯,這種寫法屬于“模式匹配”血淌,只要等號(hào)兩邊的模式相同,左邊的變量就會(huì)被賦予對(duì)應(yīng)的值财剖。
解構(gòu)賦值允許指定默認(rèn)值宙项。
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
對(duì)象的解構(gòu)賦值
數(shù)組的元素是按次序排列的,變量的取值由它的位置決定健蕊;而對(duì)象的屬性沒有次序熊痴,變量必須與屬性同名,才能取到正確的值咪橙。
let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined
如果解構(gòu)失敗夕膀,變量的值等于undefined.
對(duì)象的解構(gòu)賦值的內(nèi)部機(jī)制,是先找到同名屬性美侦,然后再賦給對(duì)應(yīng)的變量产舞。真正被賦值的是后者,而不是前者菠剩。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
上面代碼中易猫,foo是匹配的模式,baz才是變量具壮。真正被賦值的是變量baz准颓,而不是模式foo哈蝇。
對(duì)象的解構(gòu)也可以指定默認(rèn)值。
默認(rèn)值生效的條件是攘已,對(duì)象的屬性值嚴(yán)格等于undefined炮赦。
函數(shù)的擴(kuò)展
ES6 之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值贯被,只能采用變通的方法眼五。
if (typeof y === 'undefined') {
y = 'World';
}
判斷參數(shù)y是否被賦值。
ES6 允許為函數(shù)的參數(shù)設(shè)置默認(rèn)值彤灶,即直接寫在參數(shù)定義的后面看幼。
除了簡(jiǎn)潔,ES6的寫法還有兩個(gè)好處:首先幌陕,閱讀代碼的人诵姜,可以立刻意識(shí)到哪些參數(shù)是可以省略的,不用查看函數(shù)體或文檔搏熄;其次棚唆,有利于將來的代碼優(yōu)化,即使未來的版本在對(duì)外接口中心例,徹底拿掉這個(gè)參數(shù)宵凌,也不會(huì)導(dǎo)致以前的代碼無法運(yùn)行。
參數(shù)變量是默認(rèn)聲明的止后,所以不能用let或const再次聲明瞎惫。
參數(shù)默認(rèn)值可以與解構(gòu)賦值的默認(rèn)值,結(jié)合起來使用译株。
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined
上面代碼只使用了對(duì)象的解構(gòu)賦值默認(rèn)值瓜喇,沒有使用函數(shù)參數(shù)的默認(rèn)值。只有當(dāng)函數(shù)foo的參數(shù)是一個(gè)對(duì)象時(shí)歉糜,變量x和y才會(huì)通過解構(gòu)賦值生成乘寒。如果函數(shù)foo調(diào)用時(shí)沒提供參數(shù),變量x和y就不會(huì)生成匪补,從而報(bào)錯(cuò)伞辛。通過提供函數(shù)參數(shù)的默認(rèn)值,就可以避免這種情況夯缺。
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo() // undefined 5
上面代碼指定始锚,如果沒有提供參數(shù),函數(shù)foo的參數(shù)默認(rèn)為一個(gè)空對(duì)象喳逛。
一個(gè)解構(gòu)賦值的例子
function fetch(url, { body = '', method = 'GET', headers = {} }) {
console.log(method);
}
fetch('http://example.com', {})
// "GET"
fetch('http://example.com')
// 報(bào)錯(cuò)
上面代碼中,如果函數(shù)fetch的第二個(gè)參數(shù)是一個(gè)對(duì)象棵里,就可以為它的三個(gè)屬性設(shè)置默認(rèn)值润文。這種寫法不能省略第二個(gè)參數(shù)姐呐,如果結(jié)合函數(shù)參數(shù)的默認(rèn)值,就可以省略第二個(gè)參數(shù)典蝌。這時(shí)曙砂,就出現(xiàn)了雙重默認(rèn)值。
function fetch(url, { body = '', method = 'GET', headers = {} } = {}) {
console.log(method);
}
fetch('http://example.com')
// "GET"
上面代碼中骏掀,函數(shù)fetch沒有第二個(gè)參數(shù)時(shí)鸠澈,函數(shù)參數(shù)的默認(rèn)值就會(huì)生效,然后才是解構(gòu)賦值的默認(rèn)值生效截驮,變量method才會(huì)取到默認(rèn)值GET笑陈。
比較學(xué)習(xí)
// 寫法一
function m1({x = 0, y = 0} = {}) {
return [x, y];
}
// 寫法二
function m2({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
上面兩種寫法都對(duì)函數(shù)的參數(shù)設(shè)定了默認(rèn)值,區(qū)別是寫法一函數(shù)參數(shù)的默認(rèn)值是空對(duì)象葵袭,但是設(shè)置了對(duì)象解構(gòu)賦值的默認(rèn)值涵妥;寫法二函數(shù)參數(shù)的默認(rèn)值是一個(gè)有具體屬性的對(duì)象,但是沒有設(shè)置對(duì)象解構(gòu)賦值的默認(rèn)值坡锡。
// 函數(shù)沒有參數(shù)的情況
m1() // [0, 0]
m2() // [0, 0]
// x 和 y 都有值的情況
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]
// x 有值蓬网,y 無值的情況
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]
// x 和 y 都無值的情況
m1({}) // [0, 0];
m2({}) // [undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]
undefined會(huì)觸發(fā)函數(shù)默認(rèn)值,null不會(huì)