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...