title: ECMAScript 6 - 解構(gòu)賦值
date: 2017年7月31日 12:18:15
tags: js
categories: 教程
author: "JiaWei"
ES6 允許按照一定模式,從數(shù)組和對(duì)象中提取值,對(duì)變量進(jìn)行賦值,這被稱為解構(gòu)。
最近在學(xué)習(xí)vuex中actions的參數(shù)中使用到了對(duì)象的解構(gòu)賦值,故此前來學(xué)習(xí)了解 解構(gòu)賦值語法
-
開始
以前,為變量賦值,只能直接指定值。let a = 1; let b = 2; let c = 3;
ES6可以寫成下面這樣為變量賦值。
let [a,b,c] = [1,2,3];有關(guān)模式匹配的規(guī)則:
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
關(guān)于解構(gòu)賦值參數(shù)不完整的情況:
let [foo] = [];
let [bar, foo] = [1];
解構(gòu)不成功的情況下,foo的值等于undefined
let [x,y] = [1,2,3];
x // 1 ,y // 2
let [a,[b],d] = [a,[2,3],4];
a // 1 , b //2 ,d // 4
上面兩個(gè)栗子,都屬于不完全解構(gòu),但都可以成功。
如果等號(hào)的右邊不是可遍歷的結(jié)構(gòu)(數(shù)組,Set)那么將會(huì)報(bào)錯(cuò)。
// 編譯報(bào)錯(cuò)
let[foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
對(duì)于Set結(jié)構(gòu)進(jìn)行解構(gòu)賦值。
let [x,y,z] = new Set([1,2,3]);
x // 1
** 解構(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'
- ES6 內(nèi)部使用嚴(yán)格相等運(yùn)算符(===),判斷一個(gè)位置是否有值。如果一個(gè)數(shù)組成員不嚴(yán)格等于undefined,默認(rèn)值是不會(huì)生效的。*
let [x = 1] = [ undefined ];記得加上中括號(hào),否則報(bào)錯(cuò)
x // 1
let[ x = 1 ] = [ null ];
x // null
上面代碼中,如果一個(gè)數(shù)組成員是null,默認(rèn)值就不會(huì)生效,因?yàn)閚ull不嚴(yán)格等于undefined。
** 對(duì)象的解構(gòu)賦值 **
解構(gòu)不僅可以用于數(shù)組,還可以用于對(duì)象。
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
對(duì)象的解構(gòu)與數(shù)組有一個(gè)重要的不同。數(shù)組的元素是按次序排列的,變量的取值由它的位置決定;而對(duì)象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。
如果變量名與屬性名不一致,必須寫成下面這樣。
var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
這實(shí)際說明了對(duì)象的解構(gòu)賦值是下面形式的簡(jiǎn)寫。
let { foo: foo, bar :bar } = { foo:'aaa',bar :'bbb' };
也就是說,對(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。
** 解構(gòu)失敗 **
默認(rèn)值生效的條件是,對(duì)象的屬性值嚴(yán)格等于undefined。
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null
解構(gòu)失敗變量的值等于undefined。
let { foo } = { bar : 'baz' };
foo // undefined
如果解構(gòu)模式是嵌套的對(duì)象,而且子對(duì)象所在的父屬性不存在,那么將會(huì)報(bào)錯(cuò)。
let {foo: {bar}} = {baz: 'baz'};
對(duì)象的解構(gòu)賦值,可以很方便地將現(xiàn)有對(duì)象的方法,賦值到某個(gè)變量。
let { log, sin, cos } = Math;
上面代碼將Math對(duì)象的對(duì)數(shù)、正弦、余弦三個(gè)方法,賦值到對(duì)應(yīng)的變量上,使用起來就會(huì)方便很多。
由于數(shù)組本質(zhì)是特殊的對(duì)象,因此可以對(duì)數(shù)組進(jìn)行對(duì)象屬性的解構(gòu)。
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1 , last // 3
上面代碼對(duì)數(shù)組進(jìn)行對(duì)象解構(gòu)。數(shù)組arr的0鍵對(duì)應(yīng)的值是1,[arr.length - 1]就是2鍵,對(duì)應(yīng)的值是3。方括號(hào)這種寫法,屬于“屬性名表達(dá)式”
** 字符串的解構(gòu)賦值 **
字符串能被轉(zhuǎn)換成一個(gè)類似數(shù)組的對(duì)象,因此字符串也可以解構(gòu)賦值
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
類似數(shù)組的對(duì)象都有一個(gè)length屬性,因此還可以對(duì)這個(gè)屬性解構(gòu)賦值。
let {length : len} = 'hello';
len // 5
** 數(shù)值和布爾值的解構(gòu)賦值 **
解構(gòu)賦值時(shí),如果等號(hào)右邊是數(shù)值和布爾值,則會(huì)先轉(zhuǎn)為對(duì)象。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
上面代碼中,數(shù)值和布爾值的包裝對(duì)象都有toString屬性,因此變量s都能取到值。
解構(gòu)賦值的規(guī)則是,只要等號(hào)右邊的值不是對(duì)象或數(shù)組,就先將其轉(zhuǎn)為對(duì)象。由于undefined和null無法轉(zhuǎn)為對(duì)象,所以對(duì)它們進(jìn)行解構(gòu)賦值,都會(huì)報(bào)錯(cuò)。
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
** 函數(shù)參數(shù)的解構(gòu)賦值 **
函數(shù)的參數(shù)也可以使用解構(gòu)賦值。
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
上面代碼中,函數(shù)add的參數(shù)表面上是一個(gè)數(shù)組,但在傳入?yún)?shù)的那一刻,數(shù)組參數(shù)就被解構(gòu)成變量x和y。對(duì)于函數(shù)內(nèi)部的代碼來說,它們能感受到的參數(shù)就是x和y。
下面是另一個(gè)例子。
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
函數(shù)參數(shù)的解構(gòu)也可以使用默認(rèn)值。
function move({x = 0, y = 0} = {}) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
上面代碼中,函數(shù)move的參數(shù)是一個(gè)對(duì)象,通過對(duì)這個(gè)對(duì)象進(jìn)行解構(gòu),得到變量x和y的值。如果解構(gòu)失敗,x和y等于默認(rèn)值。
注意,下面的寫法會(huì)得到不一樣的結(jié)果。
function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
上面代碼是為函數(shù)move的參數(shù)指定默認(rèn)值,而不是為變量x和y指定默認(rèn)值,所以會(huì)得到與前一種寫法不同的結(jié)果。
undefined就會(huì)觸發(fā)函數(shù)參數(shù)的默認(rèn)值。
[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]