数组解构赋值
基本用法
- ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
- 这种写法属于
“模式匹配”
,只要等号两边的模式相同,左边的变量就会被赋予对应的值 - 如果解构不成功,变量的值就等于
undefined
。
let [a, b, c] = [1, 2, 3] // a=1, b=2, c=3
let [a, [b]] = [1, [4, 5]] // a=1, b=4 (5在这里不会进行赋值)
let[a, b, ...c] = [1, 2, 3, 4, 5] // a=1, b=2, c=[3, 4, 5]
let[a, b, c] = [1, 2] // a=1, b=2, c=undefined
以上都是数组解构赋值的例子,提一下'...c'
。它的意思是 c 在一定条件下可以被赋值为数组,如上,c被赋值为 [3, 4, 5]
=> 在 a, b 赋值完后,后面的所有值都会被 c 接纳。
如果等号的右边不是数组则会报错,一下的赋值都是不成功的。
let [a] = 1;
let [a] = false;
let [a] = NaN;
let [a] = undefined;
let [a] = null;
let [a] = {};
默认值
let [x, y = 'b'] = ['a'] // x='a', y='b'
let [x, y=4] = [10, undefined] // x=10, y=4
let [x, y=4] = [10, null] // x=10, y=null
- 虽然只是一个单词之差,但是结果却截然不同。 => ES6 内部使用严格相等运算符(===),判断一个位置是否有值。
所以,只有当一个数组成员严格等于undefined,默认值才会生效
function fn() {
console.log('javascript');
}
let [x = fn()] = [1];
// 如果默认值是表达式的话,只有在用到的时候,才会求值。
// x的默认值为fn(),但是数组中的 1 不严格等于 undefined, 所以 x 会被赋值为 1
默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
let [x = 1, y = x] = []; // x=1; y=1
let [x = y, y = 1] = []; // ReferenceError: y is not defined
// 由于在 y 还没有声明之前就将 y 的值赋给 x,所以会报错
对象解构赋值
基本用法
- 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而
对象的属性没有次序,变量必须与属性同名
,才能取到正确的值。 - 如果变量没有对应的同名属性,导致取不到值,最后等于undefined
let{a, b} = {a:'right',b:"left"};// a='right', b:'left'
let {a} = { been: 'aaa', chest: 'bbb' }; // a=undefined
- 下面代码中其实存在一个
赋值机制
,他会先在对象中找到同名属性 a,
然后再给 a属性的变量 b 进行赋值,所以最终 b=1而不是 2,两个对象是分离开来的。
let { a: b } = { a: 1, b: 2 }; // b=1
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj; // f='hello' l='world'
- 解构也可以用于嵌套结构的对象,需要注意的是,对应的结构和属性一定要匹配才赋值。
let lesson = {
plat:{
name:'Jack',
age : 18
}
}
let {plat:{name, age}} = lesson
console.log(name,age) // name='Jack', age=18
- 下面是比较复杂的结构,需要注意的是
loc:
、start:
都指的是模式,他们是不会被赋值的,只有模式下的变量才会被赋值。
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
let { loc, loc: { start }, loc: { start: { line }} } = node;
默认值
let {x, y=4} = {x:10, y:undefined} // x=10, y=4
let {x, y=4} = {x:10, y:null} // x=10, y=null
和数组结构类似,对象成员必须严格等于 'undefined'
才会允许默认值进行赋值,否则会以对象成员该值进行赋值。
函数参数的解构赋值
function fn([a,b] = [1,2]){
console.log([a, b])
}
fn([2]) // => [2, undefined]
-----------------------------
function fn([a,...b] = [1,2]){
console.log([a, b])
}
fn([2]) // => [2, Array(0)]
-------------------------------
function fn2([a=0, b=3] = []){
console.log([a, b])
}
fn2() // => [0, 3]
注意以上的三种写法:
共同点:
- 传参的位置都为等号后面,即
[1, 2],[]
,参数会对这些进行替代,不穿则默认为这些。
不同点:
- 第一和第二种是为
函数的参数 a, b
进行数组解构赋值,解构失败的话返回 undefined,不传的话默认就为 [1, 2],然后再对 [a, b] 进行解析 - 第三种表示函数的变量是一个数组,通过对数组解构对
数组的变量 a, b
进行赋值,
如果解构失败,a 和 b等于默认值
,即不传或者穿 {} 的保持默认值为 [a=0, b=0]
圆括号的使用
// 错误的写法
let x;
{x} = {x: 1};
// 正确的写法
let x;
({x} = {x: 1});
- JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
// 全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
// 报错
function f([(a)])
// 报错
function f([z,(a)])
- 上面 8个语句都会报错,因为它们都是变量声明语句,模式不能使用圆括号。
let {c:name} = ({c:'Jack'}) // 是声明语句中可以用圆括号的例外
({c:(name)} =({c:'Ben'})) //正确 => 多重括号的使用
[(b)] = [3]; // 正确
({ p: a }) = { p: 42 }; //错误
({ p: (a) } = {p: 42}); // 正确
- 在非声明语句使用,也是就是赋值语句,其次模式
p:
是不能够添加括号的 - 其实我们只需要记住,在变量声明的时候,变量不能够跟括号,赋值的对象或者数组添不添加括号不影响全局
- 其次,在赋值语句中,必须对整体添加括号,不然解析器会识别不了
应用
//最广泛的用途是函数返回多个参数
function pop(){
let a, b, c;
a = 1;
b = a + 1;
c = a*b;
return([a, b, c])
}
// 这样就解决了之前我们函数只有一个返回值的弊端