变量的解构赋值
1. 数组的解构赋值
- 基本用法
ES6允许写成下面这样
let [a, d, c] = [1, 2, 3]; //按照对应位置对变量赋值
这种写法也叫模式匹配 只要等号两边模式相同(解构成功),左边变量就会被赋予对应的值
let [head, ...tail] = [1, 2, 3, 4]; //...最后值是数组
head // 1
tail // [2, 3, 4]
解构失败,值会等于undefined
let [foo] = [];
let [bar, foo] = [1]; //foo解构不成功
另一种是不完全解构,等号左边的模式只匹配一部分的等号右边的数组(解构依然成功)
let [a, [b], c] = [1, [2, 3], 4]
a // 1
b // 2
...b b// [2,3]
c // 4
如果等号右边不是数组(也就是不可遍历的结构)那么将会报错
let [foo] = 1;
let [foo] = false; //不具备Iterator接口
...
对于set结构,也可以使用数组的解构赋值
let [x, y, z] = new Set(['a', 'b', 'c']);
x // 'a'
即,只要某种数据结构具有lterator接口,都可以采用数组形式的解构赋值
function *fibs() { //fibs是一个Generator函数,原生有Iterator接口
let a =0;
let b =1;
while (true) {
yield a;
[a,b] = [b, a + b];
}
}
let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
- 默认值
解构赋值允许指定默认值
ES6内部使用严格相等运算符(===)判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值不会生效。
let [x = 1, y = 0] = [0, null];
x // 0
y // null
let [x, y = 1] = [1, undefined];
x // 1
y // 1
默认值可引用解构赋值的其他变量,但该变量必须已经声明
let [x, y = x] = [1, 2]; //x = 1 , y = 2
let [x, y = x] = [1]; //x = 1 , y = 1
let [x = y, y = 1] = []; //ReferencceError
2. 对象的解构赋值
- 与数组的不同
数组元素是按次序排列的,变量的取值是由它的位置决定;
而对象的属性没有次序,变量必须与属性同名才能取到正确值。
let { bar, foo } = { foo: "aaa", bar: "bbb" }; //与次序无关,同名赋值
如果变量名和属性名不一致,要写成下面这样:
let { foo:baz } = { foo: "aaa", bar: "bbb" }; //baz 'aaa'
// 属性:变量 //变量赋值
所以可以知道,对象解构其实是以下这种形式:
let { bar:bar, foo:foo } = { foo: "aaa", bar: "bbb" }; //foo 'aaa'
// 属性:变量 //变量赋值
let {foo : bar} = { foo: 'bbb'};
foo // error:foo is not defined
bar // bbb
也就是说,对象的解构的内部机制是先找到同名的属性,然后在赋值给对应的变量。真正被赋值的是后者,而不是前者。
- 可用于嵌套结构的对象
let obj = {
p: [
'hello',
{ y: 'world' }
]
};
let { p: [x, { y }] } = obj;
- 可用于嵌套赋值
let obj = {};
let arr = [];
({ foo:obj.prop, bar: arr[0] } = { foo: 123, bar: true})
obj // {prop:123}
arr // [true]
- 支持默认值
默认值生效条件:对象的属性值严格等于undefined;解构失败,变量值等于undefined
var {x: y = 3} = {x: 5};
y // 5
var {x: y = 1} = {};
- 陷阱
已经声明的变量用于解构赋值,小心使用!
务必把声明变量放在圆括号里赋值
let x;
{x} = {x: 3}; //报错 {x}会被认为是一个代码块
({x} = {x: 3}) // success
- 数组进行对象解构
因为数组本质是特殊的对象,所以可以对数组进行对象解构
let arr = [1, 2, 3]; //arr 0键对应1 arr.lenght-1就是2键对应3
let {0 : first, [arr.length -1] : last} = arr;
first // 1
last // 3
3.3 字符串的解构赋值
字符串被转换成一个类似数组的对象
const [a,b,c] = 'dll';
a // 'd'
b // 'l'
c // 'l'
类似数组的对象都有一个length属性,so还可以对这个属性解构赋值
let { length : len } = 'hello';
len // 5
3.4 数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
undefined 和 null 无法转为对象,所以对它们解构赋值时都会报错
3.5 函数参数的解构赋值
- 对象和数组式传参
表面是数组,传入的那一刻,数组的值就被解构成多个变量
//数组式传参
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [3, 7]
//对象式传参
function move({x, y} = {}) {
return [x, y]
}
move({x: 1, y: 2}) // [1,2]
- 函数传参支持默认值
function move({x = 1, y = 2} = {}) {
return [x, y]
}
move({}) // [1,2]
move() // [1,2]
- 注意写法
function move({x, y} = { x: 1 , y : 2 }) {
return [x, y]
}
move({}) // [undefined, undefined]
move() // [1,2]
上面的代码为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到不同结果;undefined就会触发函数参数的默认值。
3.6 圆括号问题
ES6规则:只要有可能导致解构歧义,就不能使用圆括号;
因此在模式中尽量不用圆括号
- 不能使用圆括号的情况
- 变量声明语句
- 函数参数
- 赋值语句的模式
3.7 用途
- 交换变量的值
let x = 1 , y = 2;
[x, y] = [y, x];
- 从函数返回多个值
函数要想返回多个值要通过数组或对象;但现在就可以用解构赋值
function exp() {
return {
foo: 1,
bar: 'aaa'
};
}
let {foo, bar} = exp();
- 函数参数的定义
解构赋值可以很方便将一组参数联系起来
fuction f({x, y ,z}) { ... }
f({ x: 1, z: 2, y: 0 });
- 提取JSON数组
let people = {
age : 13,
name : 'dll',
hope : ['music','pop']
};
let { age, name, hope} =- people;
console.log(age, name, hope);
- 函数参数的默认值
指定参数的默认值,避免在函数体内部在写冗长语句(var xxx = xx.xxx || ‘xxx’)
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
//...更多配置
globale = false
}) {
// ...你要进行的操作
};
- 遍历Map结构
Map结构原生支持Iterator接口,配合变量的解构赋值获取键和键名很方便
var map = new Map();
map.set('first', 'dll');
map.set('second', 'ycy');
for(let [ket, value] of map) { // let [, value] of map 只要键值
console.log(key + 'is' + value);
}
- 输入模块的指定方法
加载模块时,往往需要指定输入的方法
const { NodeList , getURL } = require('xxx_xx');