2. 解构赋值

2/14/2022 ES6

# 0. 引子

从数组和对象中提取值,对变量进行赋值,称为解构(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,c=[]
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='NOxONE'(众所周知'NOxONE'==='吴彦祖')

# 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] = [...arguments]

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 }) {
	// {x:9,y:1}表示传参默认值
	console.log([x, y])
}

move({ x: 3, y: 8 }) // [3, 8]
move({ x: 3 }) // [3, 0]
move({}) // [0, 0], 相当于 let {x=0,y=0} = {}
move() // [9, 1] , 相当于 let {x=0,y=0} = {x:9,y: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 id = config.id || 'default id'这样的机车语句

# 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:myUserInfo } from 'user'
    我不想谋生,
    我想生活。
    红莲华
    x
    loading...