Skip to content

解构赋值

解构:自动解析数组或对象中的值,并赋值给指定的变量

数组解构

按序次排列,解构不成功 ,返回 undefined

解构空数组,原样返回

js
let [a, b, c] = [1, 2, 3]
let [foo, [[bar], baz]] = [1, [[2], 3]]
let [, , third] = ['foo', 'bar', 'baz']
let [x, y, ...z] = ['a'] // a undefined []
let [a, [b], d] = [1, [2, 3], 4, 5] // 部分解构

不能解构不可变量对象

js
// 报错
let [foo] = 1
let [foo] = false
let [foo] = NaN
let [foo] = undefined
let [foo] = null
let [foo] = {}

默认值

ES6 内部使用严格相等运算符(===),判断一个位置是否有值,就是判断是否严格等于undefined

js
let [foo = true] = [] // 指定默认值

取默认值为惰性求值

js
let [x = f()] = [1]
js
function f() {
  console.log('aaa')
}

let [x = f()] = [1] // x能解构到值,不会输出aaa

默认值引用其他变量

js
let [x = 1, y = x] = [] // x=1; y=1
let [x = 1, y = x] = [2] // x=2; y=2
let [x = 1, y = x] = [1, 2] // x=1; y=2
let [x = y, y = 1] = [] // ReferenceError: y is not defined

对象解构

对象解构

  1. 解构无次序,但要保证 解构名称与对象名称同名

  2. 解构不成功 ,返回 undefined

  3. 可以解构原型链上的变量

javascript
// 同名变量可以简写
let { bar, foo } = { foo: 'aaa', bar: 'bbb' }
const { log } = console

取别名:真正赋值的变量是别名,而不是原始名称。

js
let { first: f, last: l } = { first: 'hello', last: 'world' }

// first =>  error: is not undefined
// f => 'hello'

解构嵌套对象

js
let obj = {
  p: ['Hello', { y: 'World' }]
}

let {
  p,
  p: [x, { y }]
} = obj
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

进一步理解解构赋值中的赋值

js
let obj = {}
let arr = []

;({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true })

obj // {prop:123}
arr // [true]

默认值

js
var { x = 3 } = {}
x // 3

var { x: y = 3 } = {}
y // 3

var { x: y = 3 } = { x: 5 }
y // 5

注意点

  1. 对声明的变量进行解构
js
// 错误的写法
let x;
{x} = {x: 1}; // SyntaxError: syntax error

// 正确的写法
let x;
({x} = {x: 1});

Javascript 会将 {x} 理解为代码块

  1. 允许等号左边的模式之中,不放置任何变量名。(无意义)
js
;({} = [true, false])
;({} = 'abc')
;({} = [])
  1. 数组本质为特殊对象,可以对数组进行对象解构
js
let arr = [1, 2, 3]
let { 0: first, [arr.length - 1]: last } = arr
first // 1
last // 3

字符串解构

js
const [a, b, c, d, e] = 'hello'
let { length: len } = 'hello'

字符串会被转为类似数组的对象

数值和布尔值解构

解构赋值时,等号右边的值不是对象或数组,则会先转为对象

undefinednull无法转为对象,所以解构赋值报错

数值和布尔值的包装对象都有toString属性

js
let { toString: s } = 123
s === Number.prototype.toString // true

let { toString: s } = true
s === Boolean.prototype.toString // true

函数参数解构

js
function add([x, y]) {
  // ...
}
add([1, 2]) // 3
// 含默认值
function move({ x = 0, y = 0 } = {}) {
  return [x, y]
}
move({ x: 3, y: 8 }) // [3, 8]
move({ x: 3 }) // [3, 0]
move({}) // [0, 0]
move() // [0, 0]

function move({ x, y } = { x: 0, y: 0 }) {
  return [x, y]
}

move({ x: 3, y: 8 }) // [3, 8]
move({ x: 3 }) // [3, undefined]
move({}) // [undefined, undefined]
move() // [0, 0]

函数参数使用解构数组/对象,调用函数不传参数会报错。不能解构 undefined

js
function fn([x, y, z]) {
  console.log(x, y, z)
}
fn() //会报错

圆括号问题

以下三种情况不使用圆括号

变量声明语句

变量声明语句不能使用圆括号

js
//  全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };

函数参数

函数参数也属于变量声明

js
// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }

赋值语句

js
// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];
[({ p: a }), { x: c }] = [{}, {}];

可以使用圆括号

赋值语句,并且圆括号不属于模式(解构)一部分。

js
;[b] = [3] // 正确
;({ p: d } = {}) // 正确
;[parseInt.prop] = [3] // 正确

第一行语句中,模式是取数组的第一个成员,跟圆括号无关; 第二行语句中,模式是p,而不是d; 第三行语句与第一行语句的性质一致。

应用

(1)交换变量的值

js
;[x, y] = [y, x]

(2)从函数返回多个值 (3)函数参数的定义 (4)提取 JSON 数据 (5)函数参数的默认值 (6)遍历 Map 结构

js
const map = new Map()
map.set('first', 'hello')
map.set('second', 'world')
for (let [key, value] of map) {
  console.log(key + ' is ' + value)
}
js
// 获取键名
for (let [key] of map) {
  // ...
}

// 获取键值
for (let [, value] of map) {
  // ...
}

(7)输入模块的指定方法

js
const { SourceMapConsumer, SourceNode } = require('source-map')

相关链接

[-] 解构赋值