ES6 - 解构赋值

前言

ES6中的许多语法可以改变代码的质量,不仅限于其炫炫的书写模式。现在我们开启有关于变量解构赋值的模式,关于它的一些基本语法以及一些陷阱和注意事项。

解构(Destructuring)

这是一个很常用的,也是最简单的一种功能。可以多个变量绑定一个属性,适用于数组与对象。

1
2
3
4
5
6
var foo = { bar: 'pony', baz: 3 }
var {bar, baz} = foo
console.log(bar)
// <- 'pony'
console.log(baz)
// <- 3

从一个对象中可以很快地获取一个特定属性值。这里需要属性和别名映射相同。

1
2
3
4
5
6
var foo = { bar: 'pony', baz: 3 }
var {bar: a, baz: b} = foo
console.log(a)
// <- 'pony'
console.log(b)
// <- 3

当然,可以存在多层嵌套,只需“模式匹配”。

1
2
3
4
5
6
var foo = { bar: { deep: 'pony', dangerouslySetInnerHTML: 'lol' } }
var {bar: { deep, dangerouslySetInnerHTML: sure }} = foo
console.log(deep)
// <- 'pony'
console.log(sure)
// <- 'lol'

默认情况下,属性找不到对应值就会被定义为undefined,就像是对象使用点或括号访问属性时一样。

1
2
3
var {foo} = {bar: 'baz'}
console.log(foo)
// <- undefined

如果你试图获取一个不存在的嵌套的父级属性,这时就会抛出异常:

1
2
var {foo:{bar}} = {baz: 'ouch'}
// <- Exception

如果你把解构理解为ES5中的语法糖,会更加容易理解:

1
2
3
var _temp = { baz: 'ouch' }
var bar = _temp.foo.bar
// <- Exception

解构一个很酷酷的特性就是,在不使用aux变量下,可以实现变量的交换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function es5 () {
var left = 10
var right = 20
var aux
if (right > left) {
aux = right
right = left
left = aux
}
}
function es6 () {
var left = 10
var right = 20
if (right > left) {
[left, right] = [right, left]
}
}

解构另外一个方便之处就是,键值可以使用计算的属性名:

1
2
3
4
var key = 'such_dynamic'
var { [key]: foo } = { such_dynamic: 'bar' }
console.log(foo)
// <- 'bar'

ES5中,便于可分配,你还需要一个额外的声明。

1
2
3
4
var key = 'such_dynamic'
var baz = { such_dynamic: 'bar' }
var foo = baz[key]
console.log(foo)

为了防止属性获取undefined,你也可以设置一个默认值。

1
2
3
4
5
6
7
8
9
var {foo=3} = { foo: 2 }
console.log(foo)
// <- 2
var {foo=3} = { foo: undefined }
console.log(foo)
// <- 3
var {foo=3} = { bar: 2 }
console.log(foo)
// <- 3

解构同样适用于数组,注意我如何在解构的一边使用方括号。

1
2
3
var [a] = [10]
console.log(a)
// <- 10

同样的,这里也可以设置默认值:

1
2
3
4
5
6
7
8
9
var [a] = []
console.log(a)
// <- undefined
var [b=10] = [undefined]
console.log(b)
// <- 10
var [c=10] = []
console.log(c)
// <- 10

可以直接获取你需要的数组元素:

1
2
3
4
5
var [,,a,b] = [1,2,3,4,5]
console.log(a)
// <- 3
console.log(b)
// <- 4

你也可以使用在解构中使用一个function参数列表:

1
2
3
4
5
6
7
function greet ({ age, name:greeting='she' }) {
console.log(`${greeting} is ${age} years old.`)
}
greet({ name: 'nico', age: 27 })
// <- 'nico is 27 years old'
greet({ age: 24 })
// <- 'she is 24 years old'

以上是一个有关于解构的粗糙讲解,那么解构的好处是什么呢?

关于解构的示例

很多情况下,使用解构将会十分方便。下面是一些最为常见的,当对象中具有一个或多个返回值时,使用解构将会变得简洁方便。

1
2
3
4
5
6
7
8
9
10
11
function getCoords () {
return {
x: 10,
y: 22
}
}
var {x, y} = getCoords()
console.log(x)
// <- 10
console.log(y)
// <- 22

类似的,当你有一堆需要默认值的选项方法时,定义默认选项。就像是Python和C#等语言中的命名参数。

1
2
3
4
5
6
7
function random ({ min=1, max=300 }) {
return Math.floor(Math.random() * (max - min)) + min
}
console.log(random({}))
// <- 174
console.log(random({max: 24}))
// <- 18

如果你想要使选项对象完全可选,可以将语法更改为:

1
2
3
4
5
function random ({ min=1, max=300 } = {}) {
return Math.floor(Math.random() * (max - min)) + min
}
console.log(random())
// <- 133

适用于解构另外一种方式类似于正则表达式,无需索引进行参数命名。这里有一个在StackOverflow找到的使用一个随意的RegExp进行URL传递的示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function getUrlParts (url) {
var magic = /^(https?):\/\/(ponyfoo\.com)(\/articles\/([a-z0-9-]+))$/
return magic.exec(url)
}
var parts = getUrlParts('http://ponyfoo.com/articles/es6-destructuring-in-depth')
var [,protocol,host,pathname,slug] = parts
console.log(protocol)
// <- 'http'
console.log(host)
// <- 'ponyfoo.com'
console.log(pathname)
// <- '/articles/es6-destructuring-in-depth'
console.log(slug)
// <- 'es6-destructuring-in-depth'
特殊示例: import 声明

尽管import声明不符合解构的规则,但其表现十分类似。下面是一个找到的类似于解构但是不是解构的示例。当你使用import书写模块声明时,你可以引入模块API中的任意模块,一个使用contra的示例:

1
2
3
4
import {series, concurrent, map } from 'contra'
series(tasks, done)
concurrent(tasks, done)
map(items, mapper, done)

你也会注意到,import声明有其不一样的语法,与解构相比较,以下的import语句均不起作用:

  • 使用默认值,import {series = noop} from 'contra'
  • 嵌套解构风格,import {map: { series }} from 'contra'
  • 别名语法,import {map: mapAsync} from 'contra'

这些限制的主要原因在于import声明有一个绑定,不是一个引用或者一个值。在模块讲解部分,我们将进行深入探索。

注:

这是一个系统学习ES6的课程,会坚持翻译,分享于大家 ~~

原文链接: ES6 JavaScript Destructuring in Depth