ES6允許按照一定的模式,從數(shù)組和對(duì)象中提取值,并對(duì)變量進(jìn)行賦值。這對(duì)于解析json數(shù)據(jù)和函數(shù)參數(shù)等操作是非常有幫助的。
數(shù)組的解構(gòu)賦值
基本用法
以前為變量賦值只能直接指定,現(xiàn)在可以這樣:
var [a, b, c] = [1, 2, 3];
console.log(c); //3
這里ES6從數(shù)組里取了對(duì)應(yīng)位置的值賦給了對(duì)應(yīng)位置的變量。
其實(shí),只要等號(hào)兩邊的模式相同,就可以成功賦值:
let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo) // 1
console.log(bar) // 2
console.log(baz) // 3
let [ , , third] = ["foo", "bar", "baz"];
console.log(third) // "baz"
let [x, , y] = [1, 2, 3];
console.log(x) // 1
console.log(y) // 3
let [head, ...tail] = [1, 2, 3, 4];
console.log(head) // 1
console.log(tail) // [2, 3, 4]
let [x, y, ...z] = ['a'];
console.log(x) // "a"
console.log(y) // undefined
console.log(z) // []
如果解構(gòu)不成功,變量的值就等于undefined。
var [foo] = [];
var [bar, foo] = [1];
foo//undefined
不完全解構(gòu)是允許的:
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
其實(shí)不止是數(shù)組可以這樣賦值,只要右邊的值被轉(zhuǎn)換為對(duì)象后具有Iterator接口就可以。如果等號(hào)右邊的值被轉(zhuǎn)換為對(duì)象后不具備Iterator接口則會(huì)報(bào)錯(cuò):
let [foo] = 1;
let [foo] = {};
Set結(jié)構(gòu)有Iterator接口,所以也可以。
let [x, y, z] = new Set(["a", "b", "c"]);
x // "a"
默認(rèn)值
解構(gòu)賦值時(shí)可以使用默認(rèn)值
var [foo = true] = [];
foo // true
[x, y = 'b'] = ['a']; // x='a', y='b'
[x, y = 'b'] = ['a', undefined]; // x='a', y='b'
function f() {
console.log('aaa');
}
//在有值時(shí),默認(rèn)值的函數(shù)不會(huì)執(zhí)行
let [x = f()] = [1];
對(duì)象的解構(gòu)賦值
解構(gòu)還可以用于對(duì)象,在對(duì)象上使用解構(gòu)時(shí)元素是按照對(duì)象的屬性名獲取并賦值的。
var { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
console.log(foo); //"aaa"
如果你要賦值的變量與對(duì)象的屬性名同名,則可以省略,不同名則要指出來(lái)。
var { foo: otherName,bar } = { foo: "aaa", bar: "bbb" };
console.log(otherName);//"aaa"
console.log(bar);//"bbb"
console.log(foo);//ReferenceError: Can't find variable: foo
嵌套賦值也是可以的:
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
console.log(obj.prop) // 123
console.log(arr[0]) // true
將已經(jīng)聲明的變量用于解構(gòu)時(shí)要格外注意:
var x;
{x} = {x: 1};// SyntaxError: syntax error
這樣的代碼會(huì)報(bào)錯(cuò),因?yàn)镴S引擎將{x}理解為一個(gè)代碼塊,從而發(fā)生語(yǔ)法錯(cuò)誤??梢圆粚⒋罄ㄌ?hào)寫(xiě)在行首,避免JS認(rèn)為這是一個(gè)代碼塊。
// 正確的寫(xiě)法
var x;
({x} = {x: 1});
對(duì)象的解構(gòu)賦值,可以將現(xiàn)有對(duì)象的方法方便的賦到某個(gè)變量來(lái)使用:
let { log, sin, cos } = Math;
字符串的解構(gòu)賦值
字符串在解構(gòu)賦值時(shí),會(huì)被轉(zhuǎn)換成一個(gè)類似數(shù)組的對(duì)象。
const [a, b, c, d, e] = 'hello';
console.log(a); // "h"
console.log(b); // "e"
console.log(c); // "l"
console.log(d); // "l"
console.log(e); // "o"
let {length : len} = 'hello';
console.log(len);// 5
數(shù)值和布爾值的解構(gòu)賦值
解構(gòu)賦值時(shí),如果等號(hào)右邊是數(shù)值和布爾值,則會(huì)先轉(zhuǎn)換為對(duì)象。這里由于Number和Boolean的包裝類都有toString方法,于是就可以賦值咯。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
函數(shù)參數(shù)的解構(gòu)賦值
原理是一樣噠,只不過(guò)使用在了函數(shù)參數(shù)上,這里使用默認(rèn)值時(shí)要注意一些。
function move({x = 0, y = 0}) {
console.log(x+"##"+y);
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // 報(bào)錯(cuò)
如果只是這樣給出默認(rèn)值就不能應(yīng)對(duì)最后一種完全沒(méi)有給解構(gòu)賦值的情形。
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]
或
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]
都好,看你想要哪種結(jié)果了。
用途
交換變量的值
這樣寫(xiě)是不是很方便~
[x, y] = [y, x];
從函數(shù)返回多個(gè)值
獲取函數(shù)返回的數(shù)組和對(duì)象也就方便啦
function example() {
return {
foo: 1,
bar: 2
};
}
var { foo, bar } = example();
函數(shù)參數(shù)的定義
// 參數(shù)是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 參數(shù)是一組無(wú)次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
提取JSON數(shù)據(jù)
var jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
函數(shù)參數(shù)默認(rèn)值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};