标签: ES6
- ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值
- 本质上属于“模式匹配”,只要等号两边模式相同,左边的变量就会被赋予相应的值
数组的解构赋值
基本用法
var [a, b, c] = [1, 2, 3]
a // 1
b // 2
c // 3
- 解构不成功,则解构不成功的变量的值为undefined
- 不完全解构,即等号左边的模式只匹配等号右边数组的一部分,则解构依然成功
let [x, y] = [1, 2, 3]
x // 1
y // 2
对于数组解构赋值,如果等式右边不是可遍历结构(本身 / 转化后的对象具备Iterator接口),将会报错
// 报错,转化后的对象不具备Iterator接口
let [a] = 1
let [b] = false
// 报错,对象本身不具备Iterator接口
let [c] = {}
// 解构成功,字符串能转换成类似数组的对象
let [d, e, f, g, h] = 'hello'
默认值
- 解构允许指定默认值
var [x, y = 2] = [1] // x=1,y=2
- 使用严格相等运算符(===)判断一个位置是否有值,仅在严格等于undefined时,默认值生效
var [x = 1] = [undefined] // x=1
var [y = 1] = [null] // y=null,默认值不生效
由于`(null===undefined)`的值为false,所以默认值不生效,`y`的值为null
- 如果默认值为一个表达式,那么这个表达式是惰性求值的,只有用到的时候才会求值
function f() {
console.log(123)
}
let [x = f()] = [1] // 无输出
- 默认值可以引用解构赋值的其他变量,但该变量必须已经声明
let [x = 1, y = x] = [] // x=1,y=1
let [a = b, b = 1] = [] // 报错
对象的解构赋值
基本用法
var { foo, bar } = { foo: 123, bar: 345 }
foo // 123
bar // 345
- 数组解构,变量的取值取决于它的位置
- 对象解构,变量必须与属性同名,才能得到正确的值
var { abc } = { foo: 123, bar: 345 }
abc // undefined
对象的解构赋值实际上是以下形式的简写
var { foo, bar } = { foo: 123, bar: 345 } // 简写
var { foo: foo, bar: bar } = { foo: 123, bar: 345 }
对象解构赋值的内部机制,是先找到同名属性,然后再赋给相应的变量。
真正被赋值的是后者,而不是前者
var { foo: baz } = { foo: 123, bar: 345 }
baz // 123
foo // Error:foo is not defined
对一个已经声明的变量解构赋值,不能将大括号 { } 写在行首,避免 javascript 将其解析为代码块
var x
({ x } = { x: 1 }) // 正确写法
{ x } = { x: 1 } // 错误写法
默认值
默认值生效的条件是,对象的属性严格等于undefined
var { message: msg = 123, x } = { message: undefined, x: null }
msg // 123
x // null
解构嵌套结构的对象
var node = {
loc: {
start: {
line: 1,
column: 5
}
}
}
var { loc: { start: { line, column } } } = node
line // 1
column // 5
loc // Error
start // Error
注意:loc 和 start 是模式,不是变量,因此不会被赋值
解构对象是嵌套的对象,而且子对象所在的父对象不存在,会报错
var { foo: { bar } } = {}
foo
为父对象,bar
为子对象,foo
不存在,报错
原因很简单:foo
这时为undefined
,再取子属性bar
就会报错
其他类型的解构赋值
字符串的解构赋值
字符串可以解构赋值,此时字符串被转换成了一个类似数组的对象
let [d, e, f, g, h] = 'hello'
var { length: len } = 'hello'
len // 5
数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值或布尔值,则先转为对象
undefined
和null
无法转为对象,会报错
let { toString: s } = 123
s === Number.prototype.toString // true
let { toString: s } = true
s === Boolean.prototype.toString // true
函数参数的解构赋值
function add([x, y]) {
return x + y
}
add([1, 2]) // 3
注意区分以下两种情况:
function move({ x = 0, y = 0 } = {}) {
return [x, y]
}
move({ x: 3, y: 1 }) // { x: 3, y: 1 }
move({ x: 3}) // { x: 3, y: 0 }
move({}) // { x: 0, y: 0 }
move() // { x: 0, y: 0 }
为解构设置默认值,当解构失败时使用默认值
move()
使用了函数默认值{}
,然后解构,解构失败,使用解构默认值
function move({} = { x = 0, y = 0 }) {
return [x, y]
}
move({ x: 3, y: 1 }) // { x: 3, y: 1 }
move({ x: 3}) // { x: 3, y: undefined }
move({}) // { x: undefined, y: undefined }
move() // { x: 0, y: 0 }
为函数设置默认值,仅当函数没有传参的时候才使用默认值
move({})
传入了空对象,所以没有使用函数默认值{}
,接下来是解构,解构失败,由于没有解构默认值,其值为undefined
变量解构的用途
交换变量的值
[x, y] = [y, x]
从函数返回多个值
function example() {
return [1, 2, 3]
}
var [a, b, c] = example()
function example() {
return {
foo: 1,
bar: 2
}
}
var { foo, bar } = example()
函数参数的定义
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3])
// 参数是一组无次序值
function f({ x, y, z }) { ... }
f({ z: 1, y: 2, x: 3 })
提取JSON数据
var jsonData = {
id: 1,
is_error: false,
result: [123, 456]
}
let { id, is_error, result } = jsonData
函数参数的默认值
jQuery.ajax = function(url, {
async = true,
beforeSend = function() {},
cache = true,
complete = function() {},
corssDomain = false,
global = true
// ... more config
}) {
// ... do stuff
}
遍历Map结构
任何部署了 Iterator接口的对象,都可以用 for...of 循环遍历
var map = new Map()
map.set('first', 'hello')
map.set('second', 'world')
for (let [key, value] of map) {
console.log(key, value)
}
// first hello
// second world
输出模块的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map")