[关闭]
@zhouweicsu 2015-09-02T04:56:08.000000Z 字数 3596 阅读 707

深入理解ES6中的解构

ES6 JavaScript


我曾在React系列文章中简短的提及过一些ES6特性(以及Babel入门),现在我想深入研究这些新的语言特性。在阅读海量ES6与ES7的文章之后,我想是时候在Pony Foo的博客中开始讨论ES6与ES7的特性了。

本文开头会给那些ES6新特性的过度使用者一些忠告。接着介绍ES6中的解构,以及解构的使用场景,还有一些陷阱和注意事项,本文是ES6系列的第一篇。

一句忠告

当你不确定时,只要能选择,都推荐选择ES5和较旧的语法,而不是ES6。我这样说并不意味着使用ES6语法是一个坏主意,恰恰相反,你看我正在写的关于ES6的文章呢!需要明确的一点是,我们使用ES6特性是因为它会提高我们的代码质量,而不仅仅因为它很酷。

目前为止我写代码都是使用简单的 ES5语法,然后在真的能提高代码质量的地方使用ES6语法糖。相信随着时间的推移,我可以更快速地识别什么情况下使用ES6而不是ES5,但在起步阶段最好不要 过于追求使用ES6的新特性。因此,你首先应该仔细分析最适合你的代码是什么,与此同时也考虑使用ES6

"通过这种方式,你就能更好的学习使用这些新特性,而不是仅仅学点语法。"

接下来,咱们就开讲这个炫酷特性!

解构

解构是ES6中最常用,也是最简单的特性之一。它允许你将数组和对象的属性赋给任何变量。

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

这样获取对象中某个特定属性将会非常简洁,当然,你也可以将这个属性赋值给某个变量。

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

你可以获取任意深度的属性,并且也可以将这些属性赋值给变量。

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

默认情况下,若解构一个未定义的属性时会得到undefined,这与使用点或者括号去访问对象的属性是一致的。

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

解构一个不存在的父级元素的深层嵌套的属性时会抛出异常。

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

假如你认为解构是像以下ES5代码中的语法糖,那么这个异常就很合理了。

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

解构还有一个超酷特性,当你交换两个变量的值时不再需要使用臭名昭著的aux变量了。

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

解构另一个特别方便的特性是keys也可以使用计算后属性名(computed property names)

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

这在ES5中,你得用一个额外的语句与临时变量来实现。

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

当你要解构的属性是undefined时你可以提供一个默认值。

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

正如前面提到的,解构在数组中也可以工作。注意我在声明变量时使用了方括号

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

数组解构与对象解构一样,也可以使用默认值。

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

在数组解构中,可以方便地跳过被解构数组中那些你不关心的元素。

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

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

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

掌握以上知识点你就知道如何使用解构了。那解构有何用呢?

解构的应用场景

解构在很多情况下都能派上用场。下面我例举一些最常用的场景。首先,我使用最多的一个场景是,在许多模块顶部的import声明中,解构可以从模块的公共API中只加载你需要的模块。举个contra的例子:

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

第二个场景,当你的方法返回一个对象时,解构也让赋值变得非常简洁。

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

举一个函数的参数使用解构的例子,假设你有一个方法,方法的参数都是可选且需设默认值的,这种情况下你可以使用解构。这与其他语言中,例如Python或者C#里的可选的命名参数一样都极其有趣。

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

如果你想让可选对象变成真正的全部可选,你可以将代码修改如下。

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

解构另外一个非常适合使用的场景就是正则表达式,你只要定义变量接收返回值,不再需要依赖数组索引再取一遍。这里有一个StackOverflow上使用正则表达式解析URL的例子。

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

【完】

原文链接:ES6 JavaScript Destructuring in Depth

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注