@zhouweicsu
2015-09-02T04:56:08.000000Z
字数 3596
阅读 935
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中最常用,也是最简单的特性之一。它允许你将数组和对象的属性赋给任何变量。
var foo = { bar: 'pony', baz: 3 }var {bar, baz} = fooconsole.log(bar)// <- 'pony'console.log(baz)// <- 3
这样获取对象中某个特定属性将会非常简洁,当然,你也可以将这个属性赋值给某个变量。
var foo = { bar: 'pony', baz: 3 }var {bar: a, baz: b} = fooconsole.log(a)// <- 'pony'console.log(b)// <- 3
你可以获取任意深度的属性,并且也可以将这些属性赋值给变量。
var foo = { bar: { deep: 'pony', dangerouslySetInnerHTML: 'lol' } }var {bar: { deep, dangerouslySetInnerHTML: sure }} = fooconsole.log(deep)// <- 'pony'console.log(sure)// <- 'lol'
默认情况下,若解构一个未定义的属性时会得到undefined,这与使用点或者括号去访问对象的属性是一致的。
var {foo} = {bar: 'baz'}console.log(foo)// <- undefined
解构一个不存在的父级元素的深层嵌套的属性时会抛出异常。
var {foo:{bar}} = {baz: 'ouch'}// <- Exception
假如你认为解构是像以下ES5代码中的语法糖,那么这个异常就很合理了。
var _temp = { baz: 'ouch' }var bar = _temp.foo.bar// <- Exception
解构还有一个超酷特性,当你交换两个变量的值时不再需要使用臭名昭著的aux变量了。
function es5 () {var left = 10var right = 20var auxif (right > left) {aux = rightright = leftleft = aux}}function es6 () {var left = 10var right = 20if (right > left) {[left, right] = [right, left]}}
解构另一个特别方便的特性是keys也可以使用计算后属性名(computed property names)。
var key = 'such_dynamic'var { [key]: foo } = { such_dynamic: 'bar' }console.log(foo)// <- 'bar'
这在ES5中,你得用一个额外的语句与临时变量来实现。
var key = 'such_dynamic'var baz = { such_dynamic: 'bar' }var foo = baz[key]console.log(foo)
当你要解构的属性是undefined时你可以提供一个默认值。
var {foo=3} = { foo: 2 }console.log(foo)// <- 2var {foo=3} = { foo: undefined }console.log(foo)// <- 3var {foo=3} = { bar: 2 }console.log(foo)// <- 3
正如前面提到的,解构在数组中也可以工作。注意我在声明变量时使用了方括号。
var [a] = [10]console.log(a)// <- 10
数组解构与对象解构一样,也可以使用默认值。
var [a] = []console.log(a)// <- undefinedvar [b=10] = [undefined]console.log(b)// <- 10var [c=10] = []console.log(c)// <- 10
在数组解构中,可以方便地跳过被解构数组中那些你不关心的元素。
var [,,a,b] = [1,2,3,4,5]console.log(a)// <- 3console.log(b)// <- 4
在一个function的参数列表中也可以使用解构。
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'
掌握以上知识点你就知道如何使用解构了。那解构有何用呢?
解构在很多情况下都能派上用场。下面我例举一些最常用的场景。首先,我使用最多的一个场景是,在许多模块顶部的import声明中,解构可以从模块的公共API中只加载你需要的模块。举个contra的例子:
import {series, concurrent, map } from 'contra'series(tasks, done)concurrent(tasks, done)map(items, mapper, done)
第二个场景,当你的方法返回一个对象时,解构也让赋值变得非常简洁。
function getCoords () {return {x: 10,y: 22}}var {x, y} = getCoords()console.log(x)// <- 10console.log(y)// <- 22
举一个函数的参数使用解构的例子,假设你有一个方法,方法的参数都是可选且需设默认值的,这种情况下你可以使用解构。这与其他语言中,例如Python或者C#里的可选的命名参数一样都极其有趣。
function random ({ min=1, max=300 }) {return Math.floor(Math.random() * (max - min)) + min}console.log(random({})) //必须输入{},否则报错// <- 174console.log(random({max: 24}))// <- 18
如果你想让可选对象变成真正的全部可选,你可以将代码修改如下。
function random ({ min=1, max=300 } = {}) {return Math.floor(Math.random() * (max - min)) + min}console.log(random()) //可以不输入{}// <- 133
解构另外一个非常适合使用的场景就是正则表达式,你只要定义变量接收返回值,不再需要依赖数组索引再取一遍。这里有一个StackOverflow上使用正则表达式解析URL的例子。
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] = partsconsole.log(protocol)// <- 'http'console.log(host)// <- 'ponyfoo.com'console.log(pathname)// <- '/articles/es6-destructuring-in-depth'console.log(slug)// <- 'es6-destructuring-in-depth'
【完】