ES6允许按照一定的模式,从数组和对象中提取值,并对变量进行赋值。这对于解析json数据和函数参数等操作是非常有帮助的。
数组的解构赋值
基本用法
以前为变量赋值只能直接指定,现在可以这样:
var [a, b, c] = [1, 2, 3];
console.log(c); //3
这里ES6从数组里取了对应位置的值赋给了对应位置的变量。
其实,只要等号两边的模式相同,就可以成功赋值:
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) // []
如果解构不成功,变量的值就等于undefined。
var [foo] = [];
var [bar, foo] = [1];
foo//undefined
不完全解构是允许的:
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
其实不止是数组可以这样赋值,只要右边的值被转换为对象后具有Iterator接口就可以。如果等号右边的值被转换为对象后不具备Iterator接口则会报错:
let [foo] = 1;
let [foo] = {};
Set结构有Iterator接口,所以也可以。
let [x, y, z] = new Set(["a", "b", "c"]);
x // "a"
默认值
解构赋值时可以使用默认值
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');
}
//在有值时,默认值的函数不会执行
let [x = f()] = [1];
对象的解构赋值
解构还可以用于对象,在对象上使用解构时元素是按照对象的属性名获取并赋值的。
var { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
console.log(foo); //"aaa"
如果你要赋值的变量与对象的属性名同名,则可以省略,不同名则要指出来。
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
将已经声明的变量用于解构时要格外注意:
var x;
{x} = {x: 1};// SyntaxError: syntax error
这样的代码会报错,因为JS引擎将{x}理解为一个代码块,从而发生语法错误。可以不将大括号写在行首,避免JS认为这是一个代码块。
// 正确的写法
var x;
({x} = {x: 1});
对象的解构赋值,可以将现有对象的方法方便的赋到某个变量来使用:
let { log, sin, cos } = Math;
字符串的解构赋值
字符串在解构赋值时,会被转换成一个类似数组的对象。
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
数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转换为对象。这里由于Number和Boolean的包装类都有toString方法,于是就可以赋值咯。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
函数参数的解构赋值
原理是一样哒,只不过使用在了函数参数上,这里使用默认值时要注意一些。
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(); // 报错
如果只是这样给出默认值就不能应对最后一种完全没有给解构赋值的情形。
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]
都好,看你想要哪种结果了。
用途
交换变量的值
这样写是不是很方便~
[x, y] = [y, x];
从函数返回多个值
获取函数返回的数组和对象也就方便啦
function example() {
return {
foo: 1,
bar: 2
};
}
var { foo, bar } = example();
函数参数的定义
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
提取JSON数据
var jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
函数参数默认值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};