引子
从数组和对象中提取值,对变量进行赋值,称为解构(Destructuring)
1.Array解构
1.1 正常解构
let [a, b, c] = [1, 2, 3] // a=1,b=2,c=3
1.2 花里胡哨解构(看看就行)
let [a, , b] = [1, 2, 3] // a=1,b=2
let [a, b, ...c] = [1] // a=1,b=undefined,z=[]
let [a, [[b, c], d]] = [1, [[2, 3], 4]] // 你猜~
let [a, [b], d] = [1, [2, 3], 4] // a=1,b=2,d=4
// set也可以解构
let [x, y, z] = new Set([1, 2, 3]) // x=1,y=2,z=3
1.3 解构允许默认值,若位置无值(undefined
),默认值会替代
let [x, y = 2] = [1] // x=1, y=2
let [x, y = 2] = [1, undefined] // x=1, y=2
let [x = 1] = [undefined] // x=1
// null非undefined
let [x = 1] = [null] // x=null
2. Object解构
2.1 属性解构
let {id, name} = {name:'吴彦祖',id:7} // id=7,name='肖宇晨'(众所周知'肖宇晨'==='吴彦祖')
2.2 方法解构
const{ log } = console
log(7) // 7
let {sin, cos, random, abs} = Math
abs(-7) // 7
// 是不是解锁了新天地?
2.3 变量可以与要解构的属性不同名
其实之前的例子里的变量要与解构的属性同名是因为
let {id, name} = {id: 1007, name: 'jack'}
// 等价于
let {id: id, name: name} = {id: 1007, name: 'jack'}
也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量
。真正被赋值的是后者,而非前者
let {id: uid} = {id: 1007} // uid:1007
2.4 花里胡哨解构(看看就行)
let obj = {
p: ['Hello',{ y: 'World' }]
}
let { p, p: [x, { y }] } = obj // p:["Hello", {y: "World"}], x='hello',y='world'
let obj = {}
let arr = []
({ id: obj.prop, flag: arr[0] } = { id: 123, flag: true }) // 加括号强制执行,而无需加let、const
// obj={prop:123}, arr = [true]
// 数组本质上是特殊对象,属性为index
let arr = [1, 2, 3]
let {0:first, [arr.length - 1] : last} = arr // first=1,last=3
对象的解构赋值可以取到继承的属性
const obj = {}
Object.setPrototypeOf(obj, {id:107})
const { id } = obj // id=107
2.5 解构默认值
var {x: y = 3} = {} // y=3
var {x: y = 3} = {x: 5} // y=5
var {x = 3} = {x: undefined} // x=3
var {x = 3} = {x: null}// x=null
3.String的解构 (看看就行)
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象
const [a, b, c] = 'xyz' // a='x',b='y',c='z'
// String转对象
String: {
'0': 'x',
'1': 'y',
'2': 'z',
length: 3
}
4.Number和Boolean解构 (看看就行)
let {toString: s} = 123
s === Number.prototype.toString // true,实际上是解构原型上的方法
let {toString: s} = true
s === Boolean.prototype.toString // true
5.函数参数的解构
函数调用时传参会发生隐式解构
,即let [arg1,...,arg2] = [].prototype.slice.call(arguments,0)
function add([x, y]){
return x + y
}
add([1, 2]) // 3
// 相当于 let [x,y] = [1,2]
5.1 传参隐式解构
[[1, 2], [3, 4]].map(([a, b]) => a + b) // [3,7]
// 相当于
// 第一次map
let [a,b] = [1,2]
// 第二次map
let [a,b] = [3,4]
5.2 解构默认值
function f(x, y = 5, z) {
return [x, y, z]
}
f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]
function move({x = 0, y = 0} = {x:9,y:1}) {
console.log([x,y])
}
move({x:3,y:8}) // [3, 8]
move({x:3}) // [3, 0]
move({}) // [0, 0] // 相当于 {x=0,y=0}={}
move() // [9, 1]
☆6.解构的应用场景
6.1 变量交换
let x = 1
let y = 2
[x, y] = [y, x]
6.2 解构函数返回值
function fn() {
return [1, 2, 3]
}
let [a, b, c] = fn()
function fn() {
return {name: 'jack',id: 107}
}
let {name:uName,id:uId} = fn() // uName='jack', uId=107
6.3 函数参数解构
function fn({x,y,z}) {
return x+y+z
}
fn({z:3,y:2,x:1})
6.4 提取 JSON 数据
let jsonData = {
id: 1007,
name: 'jack',
data: ['LiNing', 'Anta']
}
let {id, name, data: brands } = jsonData
6.5 函数参数默认值
// 定义默认配置
jQuery.ajax = function (url, {
async=true,
beforeSend=function() {},
cache=true,
id=12
} = {}) {
//....
}
jQuery.ajax('www.baidu.com',{
async: false,
cache: false,
// 这里只改变两个配置项,其他配置项不传入代表默认
})
这样就避免了函数体内部类似 let foo = config.foo || 'default foo'
这样的机车语句
6.6 遍历 Map 结构
const map = new Map()
map.set('id', 107)
map.set('name', 'jack')
// [['id',107],['name': 'jack']]
// 获取键值对
for (let [key, value] of map) {
console.log(key + " is " + value)
}
// 只获取键名
for (let [key] of map) {
// ...
}
// 只获取键值
for (let [,value] of map) {
// ...
}
6.7 引入模块的指定方法
const { getId, getUserInfo} = require('user')
import { getId, getUserInfo } from 'user'