ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为 解构(Destructuring)
ES6 之前, 声明多个变量我们可以这样子
var a = 1,
b = 2,
c = 3
而 ES6 增加了解构赋值, 赋值变得更加的高大上了
var [a, b, c] = [1, 2, 3]
1. 数组的解构赋值
下面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
let [a, b, c] = [1, 2, 3]
// 解构不成功的情况下,该变量的值为 undefined
let [a, b, ...c] = [1] // a: 1, b: undefined, c: []
// 不完全解构,也可以成功
let [a, [b], c] = [1, [2, 3], 4] // a: 4, b: 2, c: 4
// 等号的右边不是数组( 不是可遍历的结构 )的话, 会报错
let [foo] = 1
// 对于 Set 结构,也可以使用数组的解构赋值。
let [x, y, z] = new Set(['a', 'b', 'c'])
结解构赋值允许指定默认值
当对应的数组成员值为 undefined 时, 默认值才生效, 可以引用已声明的解构赋值的其它变量
let [x, y = 2] = [1]
let [x, y = 'b'] = ['a', undefined]
let [x = 1, y = x] = []
当默认值为表达式的时候, 那么这个表达式是惰性求值的(要用到的时候才执行), 像下面的情况, f 函数根本没有执行
function f () {
console.log('aaa')
}
let [x = f()] = [1]
2. 对象的解构赋值
数组的解构赋值的成员变量是由排序位置决定, 一一对应的, 但是对象没有次序, 所以就要求变量和属性必须同名。
// 变量和同名的属性一一对应
let {x, y} = {x: 1, y: 2}
x // 1
y // 2
// 等号右边没有对应的同名属性, 所以取不到值
let {z} = {x: 1, y: 2}
z // undefined
// 上面是下面形式的简写
let {x: x, y: y} = {x: 1, y: 2}
x // 1
y // 2
let {z: z} = {x: 1, y: 2}
z // undefined
// 这么写就能取到值了, 注意被赋值的是后者
let {x: z} = {x: 1, y: 2}
z // 1
x // error: x is not defined
数组的解构赋值可以用于嵌套结构
// 用于嵌套结构
let obj = {
p: [
'hello',
{ y: 'world' }
]
}
let {p: [x, {y}]} = obj
x // 'hello'
y // 'world'
let {p, p: [x, {y}]} = obj
x // 'hello'
y // 'world'
p // [ 'hello', { y: 'world' } ]
// 来多个例子
let obj = {}
let arr = []
// 因为如果以 ‘{’ 开头的话, 被 ‘{’ 和 ‘}’ 包裹起来的区域会被视为一个代码块
// 加上括号以后, 可以避免这个问题
({foo: obj.prop, bar: arr[0] } = {foo: 1, bar: 2})
{foo: obj.prop, bar: arr[0] } = {foo: 1, bar: 2} // 会报错
obj // {prop: 1}
arr // [2]
数组的解构赋值可以给变量指定默认值,默认值生效的条件是同名属性为 undefined
// 对应的 x 属性 为undefined,默认值生效
let {x: y= 3} = {}
y // 3
// 对应的 x 属性 不为undefined,默认值不生效
let {x: y= 3} = {x: 2}
y // 2
let {msg: msg= 'no msg'} = {}
msg // no msg
let {msg: msg= 'no msg'} = {msg: null}
msg // null
let {msg: msg= 'no msg'} = {msg: 'this is a msg'}
msg // this is a msg
// 使用解构赋值, 可以将对象的方法赋值给变量
let {log, sin, cos} = Math
数组其实就是特殊的对象, 所以也可以对数组进行对象属性的解构
let arr = [2, 4, 6]
let {0: first, [arr.length - 1]: last} = arr
first // 2
last // 6
上面代码中,有个是属于 未学到的 ES6 的内容。当对象的属性为表达式的时候,可以使用 arr[arr.length - 1] 的形式,将表达式放在 方括号中,到了 ES6,使用字面量定义对象的时候,也允许使用表达式作为属性名,同样的也是把表达式放在 方括号中
3.字符串的解构赋值
字符串在进行解构赋值的时候会转换成类似数组的对象
const [a, b, c, d, e] = 'hello'
a // 'h'
// 字符串有个 length 属性
let {length: len} = 'hello'
len // 5
4.数值和布尔值的解构赋值
解构赋值的时候, 都会等号右边的值转换成对象
let {valueOf: v} = 123
v = Number.prototype.valueOf // true
let {valueOf: v} = true
v = Number.prototype.valueOf // true
当右边的值无法转为对象的时候, 会提示语法错误
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
5.函数参数的解构赋值
function add([x, y]) {
return x + y
}
add([1, 2]) // 3
// 使用默认值
function move({x = 0, y = 0} = {}) {
return [x, y]
}
move({x: 1, y: 2}) // [1, 2]
move({}) // [0, 0]
move() // [0, 0]
上面的代码是为 x 和 y 指定默认值, 而下面的代码将为函数 move 的参数指定默认值
function move({x, y} = {x: 0, y: 0}) {
return [x, y]
}
move({x: 1, y: 2}) // [1, 2]
move({x: 1}) // [1, undefined]
move({}) // [undefined, undefined]
move() // [0, 0]
6. 圆括号的问题
// 变量声明语句的模式不能使用圆括号
let [(a)] = [1] // 报错
// 下面的代码就可以
[(a)] = [1]
// 函数参数也属于变量声明,所以也不能使用圆括号
function f([(a)]) {return a} // 报错
// 赋值操作的时候,将整个模式或部分模式都放在圆括号中都是会报错的
([a]) = [1]
[({x: x}), y] = [{x: 2}, 3]
7. 总结用途
(1)交换变量的值
let x = 1
let y = 2
let [x, y] = [y, x]
(2)从函数返回多个值
function f() {
return [1, 2, 3]
}
let [first, second, third] = f()
first // 1
second // 2
third // 3
function getName() {
return {firstName:'allen', lastName:'iverson'}
}
let {firstName, lastName} = getName()
firstName // allen
lastName // iverson
(3)函数参数的定义
function add([x, y]) {
return x + y
}
add([1, 2]) // 3
function getFullName({firstName, lastName} = {}) {
return firstName + ' ' + lastName
}
getFullName({firstName: 'allen', lastName: 'iverson'})
(4)提取 JSON 数据
let jsonData = {
id: 40,
data: [23, 43, 34]
}
let {id, data: number} = jsonData
id // 40
number // [23, 43, 34]
(5)函数参数的默认值
function F(id, {
x = false,
y = true,
cb = function () {}
}) {
// ....
}
(6)遍历Map结构
const 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
// 只获取键名
for (let [key] of map) {
// ...
}
// 只获取键值
for (let [, value] of map) {
// ...
}
(7)输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map")