变量的解构赋值
一、为什么要使用解构赋值?
在学习ES6新的特性解构赋值之前,我们先来看看为什么要使用解构,以前如果我们需要获取对象或者数组里面的数据,并且把它们存入数组,需要写很多代码。如下
const person = {
name: 'MengXiangJi',
age: 18,
sex: '男'
}
let age = person.age
let name = person.name
let sex = person.sex
我们想在一个对象中获取相应的数据,需要写很多重复的代码,基于此,es6为我们推出了解构赋值这个特性。我们可以更简单的获取对象或者数组中的数据。
二、什么是解构赋值
解构赋值语法是一个Javascript表达式,这使得可以将数据从数组或对象提取到不同的变量中(这段话是mdn中关于解构赋值的定义,注意这里的定义,可以看出解构主要用在数组和对象上)。
还是上面这个需求,如果我们使用解构赋值的方法,那么书写方式如下
const person = {
name: 'MengXiangJi',
age: 18,
sex: '男'
}
let { name, age, sex } = person
对比之前的写法,是不是简洁了很多?
三、 对象的解构赋值
- 基本用法
对象的解构赋值,变量必须与属性同名,才能取到正确的值。
let a = {
name:'meng',
age:18
}
let {name,age} = a
console.log(name,age) // meng 18
可以起一个别名,还是上面的代码
let a = {
name:'meng',
age:18
}
let {name:b,age} = a
console.log(b,age) // meng 18
上面这段代码也可以拿到name的值
- 默认值
先来看段代码
let a = {
age:18
}
let {name ,age} = a
console.log(name,age) // undefined 18
这个时候,对象a中没有name属性,解构的时候会取不到值,所以name是undefined,这时候我们可以给name赋值一个默认值,当name严格等于undefined时,会使用默认值
let a = {
age:18
}
let {name = 111,age} = a
console.log(name,age) // 111 18
注意,下面这种是错误的写法
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error
四、数组的结构赋值
- 基本用法
let [a, b, c] = [1, 2, 3];
console.log(a,b,c) // 1 2 3
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。
let [c] = [];
console.log(c) // undefined
如果解构不成功,变量的值就等于undefined
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
如果等号的右边不是数组,那么将会报错。
- 占位
let [, , c] = [1, 2, 3];
console.log(c) // 3
如果我们只想拿到3的话,可以用逗号进行占位
- 不完全解构
let [x, y] = [1, 2, 3];
console.log(x,y) // 1 2
即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
- 默认值
let [foo = true] = [];
foo // true
这里的默认值使用方法和对象的一样
五、字符串的解构赋值
- 基本用法
const [a, b, c, d] = 'meng';
console.log(a,b,c,d) // m e n g
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
六、函数参数的解构赋
- 基本用法
function a([x, y]){
return x + y;
}
a([1, 2]); // 3
函数a的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量x和y。对于函数内部的代码来说,它们能感受到的参数就是x和y。
- 默认值
function a([x , y = 5]){
return x + y;
}
a([2]); // 7
七、圆括号的问题
解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。
由此带来的问题是,如果模式中出现圆括号怎么处理。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。
但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号。
- 不能使用圆括号的情况
变量声明语句
// 全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
函数参数
// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }
赋值语句的模式
// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];
- 可以使用圆括号的情况
可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
上面三行语句都可以正确执行,因为首先它们都是赋值语句,而不是声明语句;其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性质一致。