ES6中允许按照一定的模式从数组和对象中提取值,然后对变量进行赋值,这就是解构。
在没有解构赋值前只能直接定值:
let a = 1;
let b = 2;
let c = 3;
ES6中允许写成下面这样:
let [a, b, c] = [1, 2, 3]
console.log(a, b, c); //1,2,3
例:
let [foo, [[bar], baz]] = [10, [[20], 30]]
console.log(foo, bar, baz); //10,20,30
let [, , third] = ["foo", "bar", "baz"];
console.log(third); //baz
let [x, , y] = [1, 2, 3]
console.log(x,y);//1 3
let [head,...tail] = [1,2,3,4,5];
console.log(head);//1
console.log(tail);//[2, 3, 4, 5]
let [x,y,...z] = "a";
console.log(x,y,z);//a undefined []
如果解构不成功,变量的值就等于undefined
例:
let [foo] = [];
let [bar,baz] = [1];
console.log(foo,baz);//undefined undefined
另一种情况是不完全解构:就是等号左边的模式只匹配一部分等号右边的数组,这样解构依然可以成功
例:
let [x,y] = [1,2,3];
let [a,b,c] = [1,[2,3],4]
如果等号的右边不是数组(或者说不是可遍历的解构),那么会报错
例:下面的语句都会报错,因为等号右边的值或是转为对象以后不具备Iterator接口,或者是本身就不具备Iterator接口
let [foo] = 1;//TypeError: 1 is not iterable
let [foo] = false;//TypeError: false is not iterable
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
let [x,y,z] = new Set(['a','b','b','c']);
console.log(x,y,z);//a b c
let [foo = true] = [];
console.log(foo);//true
let [a,b="1"] = ["2"]
console.log(a,b);//2 1
let [x,y="b"] = ["a",undefined];
console.log(x,y);//a b
注意:ES6 内部使用严格相等运算符(===)判断一个位置是否有值,所以如果一个数组成员不===undefined,默认值就不会生效
let [x=1] = [undefined];
console.log(x);//1
let [y=2] = [null];
console.log(y);//null
如果默认值为一个表达式,那么这个表达式是惰性求值,只有在用到时才会求值
所以下面的代码中因为x能取到值,所以函数f根本不会执行
function f() {
console.log("aaa");
}
let [x = f()] = [1];
console.log(x);//1
默认值也可以引用解构赋值的其他变量,但是变量必须已经声明。
let [x = 1, y = x] = [];
console.log(x, y); //1,1
let [x = 1, y = x] = [2];
console.log(x, y);//2,2
let [x = y, y = 2] = [];//报错 因为x用到默认值y的时候,y还没有声明
解构不仅可以用于数组,还可以用于对象。
注意:对象的解构赋值的内部机制是先找到同名属性,然后再赋值给对应的变量,真正被赋值的是后者,而不是前者
例:
let {foo,bar } = {foo:"aaa",bar:"bbb"};
console.log(foo,bar);//aaa bbb
let {bar,foo} = {foo:"aaa",bar:"bbb"};
console.log(bar,foo);//bbb aaa
let {baz} = {foo:"aaa",bar:"bbb"};
console.log(baz);//undefined
例:
var {foo:baz} = {foo:'aaa',bar:'bbb'};
console.log(baz);//aaa
console.log(foo);//错误 foo is not defined
let obj = {
first: 'hello',
last: 'world'
}
let {first:f,last: l } = obj;
console.log(f,l);//hello world
let obj = {
p:[
'Hello',
{y:"world"}
]
}
let {p:[a,{y}]} = obj;
console.log(a,y);//Hello world
上面的的p是模式,不是变量,因此不会被赋值,如果p也要作为变量赋值,则需要写成下面这样
let {p,p:[a,{y}]} = obj;
再来看一个案例:下面的代码有三次解构赋值,分别是对loc、start、line三个属性的解构赋值。需要注意的是,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式
var node = {
loc:{
start:{
line:1,
column:5
}
}
}
var {loc,loc:{start},loc:{start:{line}}}=node
console.log(line);//1
console.log(loc);//Object {start:Object}
console.log(start);//Object {line: 1, column: 5}
//数组的本质是特殊的对象,因此可以对数组进行对象属性的解构
let arr =[1,2,3];
let {0:first,[arr.length-1]:last} = arr;
console.log(first,last);//1 3
字符串也可以解构赋值,这是因为字符串被转换成了一个类似数组的对象
const [a,b,c,d] = "hello";
console.log(a,b,c,d);//h e l l
类似数组的对象都有一个length属性,因此还可以对这个属性进行解构赋值
let {length:len} = "hello";
console.log(len);//5
解构赋值的时候,如果等号右边的是数值和布尔值,则会先转为对象
数值和布尔值的包装对象都有toString属性,所以变量s都能取到值
let {toString:s} = 123;
console.log(s == Number.prototype.toString);//true
let {toString:s} = true;
console.log(s == Boolean.prototype.toString);//true
解构赋值的规则是,只要等号右边的值不是对象或者数组,就先将其转换成对象。
由于undefined和null无法转对象,所以对他们进行解构赋值的时候会报错
let {b} = undefined;//报错
let {c} = null;//报错
function add([x, y]) {
return x + y;
}
console.log(add([2, 3])); //5
function move({x = 0,y = 0} = {}) {
return [x, y];
}
console.log(move()); //[0, 0]
console.log(move2({})); //[0,0]
console.log(move({
x: 1
})); //[1, 0]
console.log(move({
x: 2,
y: 4
})); //[2, 4]
注意下面的写法会得到不一样的结果,下面的代码是给函数的参数设置默认值,而不是变量x和y
function move2({x,y} = {x: 0,y: 0}) {
return [x, y]
}
console.log(move2({x: 2,y: 4})); //[2, 4]
console.log(move2({x: 2})); //[2, undefined]
console.log(move2({})); //[undefined, undefined]
console.log(move2()); //[0, 0]
let x = 123;
let y = 666;
[x, y] = [y, x];
console.log(x, y); //666 123
//返回一个数组
function exam1() {
return [1, 2, 3];
}
let [a, b, c] = exam1();
console.log(a, b, c); //1 2 3
//返回一个对象
function exam2() {
return {
name: "张三",
age: 18
}
}
let {name,age} = exam2();
console.log(name, age); //张三 18
//参数是一组有次序的值
function fn1([x, y, z]) {
//...
console.log(x,y,z);
}
fn1([1,2,3]);
//参数是一组无次序的值
function fn2({x,y,z}) {
//...
console.log(x,y,z);
}
fn2({z:20,y:19,x:18})
解构赋值对提取JSON对象中的数据尤其重要
let jsonData = {
id:42,
status:"OK",
data:[666,777],
}
let {id,status,data} = jsonData;
console.log(id ,status,data);//42 "OK" [666, 777]
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。