目录:
- 数组的解构赋值
- 对象的解构赋值
- 字符串的解构赋值
- 数值和布尔值的解构赋值
- 函数参数的解构赋值
- 用途
ES6允许按照一定的模式从数组和对象中提取值,然后从变量进行赋值,这种方式被称为解构赋值。
数组的结构赋值
以前为变量的赋值只能直接指定值
let a = 1;
let b = 2;
let c = 3;
在ES6中允许写成这样的:let [a,b,c] = [1,2,3]
,这种方式表示可以从数组中提取值,并按照对应的位置对变量赋值。本质上这种写法属于“匹配模式”,只要等号两边的模式相同,左边的变量就会被赋予对应得值,下面是一个嵌套数组进行解构赋值得例子。
let [foo,[[bar],baz]] = [1,[[2],3]];
foo//1
bar//2
baz//3
从上面得例子中我们可以看到数组得解构赋值其实是等号两边的数组的相对应位置上的值赋值:请看下面的例子
//例一:
let [foo,[[bar],baz]] = [1,[[2,4],3]];
foo//1
bar//2
baz//3
//例二
let [foo,[[bar],baz]] = [1,[[],3]];
foo//1
bar//undefind
baz//3
从上面的两个例子中可以看出来,如果等号右边的数组对应位置上为空,则等号左边的对应位会被赋值为undefined,如果等号右边有非对应位则不会影响等号左边的值赋值。
如果等号左边为数组而等号右边为非数组(或者不是可遍历的结构)则会报错,下面的例子都会报错
let [foo] = 1;
let [foo] = true;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
上面的例子都会报错,因为等号右边的值或是转为对象以后不具备Iterator接口(前五个表达式),或是本身就不具备Iterator(最后一个表达式)。
对于Set结构,也可以使用数组的解构赋值
let [x,y,z] = new Set(['a','b','c']);
x//'a'
这是因为new Set()对象会返回一个没有重复值的数组,所以具有Iterator接口,都可以采用数组形式的解构赋值。
数组的结构赋值是可以指定默认值的 :
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的内部使用严格的 “===”判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的,上面最后一个例子中等号右边第二个值为undefined,所以默认值生效了。
从上面我们知道了,当一个数组成员严格等于undefined时,默认值才会生效,所以当一个数组成员等于null时候不会使用默认值。
let [x] = [null];
x//null
对象的解构赋值
不仅数组可以结构赋值,对象也可以解构赋值,在数组中解构赋值的时候数组的元素时按次序排列的,变量的取值是由它的位置决定的,而对象的属性没有次序,变量必须与属性同名才会赋值。意思就是说:在对象中如果有相同的属性名才有可能赋值,没有相同的属性名就会被赋值为undefined,看下面的两个例子
let {bar,foo} = {foo:"aaa",bar:"bbb"}
foo//aaa
bar//bbb
let {baz} = {foo:"aaa",bar:"bbb"}
baz//undefined
第一个例子说明了对象的解构赋值不用像数组一样来考虑对应位,第二个例子说明了如果没有同名的属性还要解构赋值的话就会被赋值为undefined.
如果变量名的属性名不一样可以写成这样:
let {foo :baz} = {foo:"aaa"}
baz//aaa
foo//undefinde
实际上对象的解构赋值是下面这种形式的简写:
let {foo:foo,bar:bar} = {foo:"aaa",bar:"bbb"}
也就是说对象的解构赋值的内部机制就是先去找同名属性,然后再赋值给对应的变量,真正被赋值的是后者,而不是前者。
上面的代码中foo是匹配机智,baz才是变量,通俗易懂的说就是等号右边的对象先去等号左边找同名属性,然后把等号右边属性值赋值给等号左边的属性值(等号右边的foo先去左边找属性名也是foo的,然后把等号右边的foo对应得属性“aaa"赋值给等号左边foo对应得属性值baz),所以才会出现最后得输出baz 为”aaa“,foo为undefined
和数组一样,对象得结构赋值也可以嵌套
let obj = { p:["hello",{y:"world"}]}
let {p:[x,{y}]}
x//hello
y//world
这里得p是模式,而不是变量,因此不会被赋值,如果想被赋值,也可以写成下面这样:
let obj = { p:["hello",{y:"world"}]}
let {p,p:[x,{y}]}
x//hello
y//world
p//["hello",{y:"world"}]
对象得解构赋值也可以使用默认值
var {x = 3} = {};
x//3
var {x,y = 5} = {x:1}
x//1
y//5
默认值生效得条件也是,对象得属性值严格等于undefined
如果将一个已经声明得变量用于解构赋值,必须注意不能将大括号放在行首,因为如果放在行首JavaScript引擎会将{}理解为一个代码块,从而发生语法错误可已经{}放在()内来避免放在行首这种错误
//错误语法
let x;
{x} = {x:1};
//正确语法
let x;
({x} = {x:1})
字符串得解构赋值
字符串也可以进行解构赋值,因为此时字符串被转换成了一个类似数组得对象。
const [a,b,c,d,e] = "hello"
a//"h"
b//"e"
c//"c"
d//"d"
e//"e"
数值和布尔值的解构赋值
在解析赋值的时候,如果右边是数值和布尔值,则会转为对象
上面的代码中,数值和布尔值的包装对象都有toString属性,因此变量s都能取到值。
函数参数的解构赋值
函数的参数也可以使用解构赋值,看下面的代码
function add([x,y]){
return x + y;
}
add([1,2])//3
函数add的参数表面上是一个数组,但是在调用的时候传递的是一个数组,此时会发生解构赋值,所以数组的参数会被解构成变量x ,y ,对于函数内部来说,他们能感受到的是x和y.
函数参数的解构赋值也可以使用默认值
用途
最后我来说一下解构赋值的用途,使用结构赋值可以让我们的代码更加的简化,漂亮。但是前提是要熟练的运用,要不然就会频频报错
1.交换变量的值
在之前我们交换两个变量的值的时候都会声明一个中间变量temp来存放以下,但是使用解构赋值就不需要
let x =1;
let y =2;
[x,y] = [y,x];
使用上面的代码来交换两个变量的值是不是比之前的办法更加的简洁!!!
2.从函数中返回多个值
我们知道在函数的返回值中只能是一个变量,一个数组,一个对象,一个布尔值。。。。都是一个的,但是在ES6可以使用解构赋值来使用多个变量来接受函数的返回值。
function xxx(){
return [1,2,3];
}
let [a,b,c] = xxx()
3.函数参数的定义
解构赋值可以很方便的将一组参数与变量名对应起来
//参数是一组有序的值
function xxx([x,y,z]){}
xxx([1,2,3]);
//参数是一组无序的值
function xxx({x,y,z}){}
xxx({y:3,z:1,x:2});
4.提取JSON数据
let jsonData = {
id:42,
status:"ok",
data:[857,12]
}
let {id,status,data:number} = jsonData;
console.log(id,status,number)//42,"ok",[857,12]
5.函数参数的默认值
上面写过了
6.遍历Map结构
var map = new Map();
map.set('first','hello');
map.set('second','world');
for(let [key,value] of map){
console.log(key + "is" + value)
}
//first is hello
//second is world