ES6 中,引入了其他很多語言都具備的模式匹配
和默認參數(shù)
語法糖冤馏,使得代碼簡潔了不少。但是使用的時候還是有些細節(jié)需要注意寄啼。
模式匹配原理
模式匹配的種類
具體來說逮光,有三種類型的模式匹配:
-
直接賦值
let a = 1;
-
對象模式
let {name, age: age} = {name: 'yibuyisheng', age: 25};
-
數(shù)組模式
let [a, b] = [1, 2];
模式匹配的過程
-
直接賦值:x ← value(包括
undefined
和null
)x = value
-
對象模式
該種模式下,會檢查匹配源是不是對象墩划,如果不是對象涕刚,則會使用內(nèi)部的 ToObject() 進行轉(zhuǎn)換。
-
{?properties?} ← undefined
throw new TypeError();
-
{?properties?} ← null
throw new TypeError();
-
{key: ?pattern?, ?properties?} ← obj
?pattern? ← obj.key {?properties?} ← obj
-
{key: ?pattern? = default_value, ?properties?} ← obj
let tmp = obj.key; if (tmp !== undefined) { ?pattern? ← tmp } else { ?pattern? ← default_value } {?properties?} ← obj
-
{} ← obj
// No properties left, nothing to do
-
-
數(shù)組模式
該種模式下走诞,右側(cè)必須是可迭代的副女,如果不可迭代,就會拋出錯誤。
-
[?elements?] ← non_iterable
assert(!isIterable(non_iterable)) throw new TypeError();
-
[?elements?] ← iterable
assert(isIterable(iterable)) let iterator = iterable[Symbol.iterator](); ?elements? ← iterator
-
模式匹配中需要注意的
undefined 觸發(fā)默認值
如下所示:
let [x = 1] = [undefined]; // x = 1
右側(cè)的 underfined
元素會觸發(fā)左側(cè)的默認值碑幅。
在需要的時候才會去計算默認值
比如:
let {prop: y = someFunc()} = someValue;
只有在右側(cè) someValue.prop
為 undefined
的時候才會執(zhí)行 someFunc()
函數(shù)戴陡。
模式匹配中可以引用模式中前面的變量
比如:
let [x = 3, y = x] = [7, 2]; // x=7; y=2
這個地方要注意順序,比如下面這個就是錯誤的:
let [x = y, y = 3] = [7, 2]; // ReferenceError
函數(shù)參數(shù)傳遞
函數(shù)傳參的過程沟涨,實際上就包含了模式匹配的過程:
function func(?FORMAL_PARAMETERS?) {
?CODE?
}
func(?ACTUAL_PARAMETERS?);
// 大致是:
{
let [?FORMAL_PARAMETERS?] = [?ACTUAL_PARAMETERS?];
{
?CODE?
}
}
函數(shù)默認參數(shù)恤批,慎用對象引用
有如下示例代碼:
let list = [];
function fn(a = list) {
console.log(a);
}
fn(); // console.log: []
list.push(1);
fn(); // console.log: [1]
默認參數(shù)使用了 list 引用,那么后續(xù)對 list 的修改裹赴,都會體現(xiàn)到默認參數(shù)上面去喜庞。在大型項目開發(fā)中,容易失控棋返。如果一定要用某個變量生成默認值延都,建議深拷貝一份:
let list = [];
const listDefaultParam = deepClone(list); // 其它地方不要再使用這個變量了,并且在函數(shù)內(nèi)部也不要修改這個變量值
function fn(a = listDefaultParam) {
console.log(a);
}
默認參數(shù)的作用域
使用最新版的 Chrome 瀏覽器執(zhí)行下面的代碼睛竣,注意輸出結果:
({
method() {
function innerFn(a = () => console.log(this)) {
a();
}
innerFn.call(this);
}
}).method();
({
method() {
function innerFn(a = () => console.log(this)) {
a();
}
innerFn();
}
}).method();
({
method() {
let arrowFn = () => console.log(this);
function innerFn(a = arrowFn) {
a();
}
innerFn();
}
}).method();
({
method() {
let arrowFn = () => console.log(this);
function innerFn(a = arrowFn) {
a();
}
innerFn.call(this);
}
}).method();
// output:
//
// Object({method: ()})
// Window { ... }
// Object({method: ()})
// Object({method: ()})
實際上晰房,將上述代碼用 babel 轉(zhuǎn)換一下,可以發(fā)現(xiàn)默認參數(shù)的處理過程發(fā)生在函數(shù)開始部分射沟。