es6
1. ES6中的默认参数
var link = function (height, color, url) {
var height = height || 50
var color = color || 'red'
var url = url || 'http://azat.co'
}
2. ES6中的模版表达式
模版表达式在其他语言中一般是为了在模版字符串中输出变量,所以在ES5中,我们非得把字符串破开变成这样:
var name = 'Your name is ' + first + ' ' + last + '.'
var url = 'http://localhost:3000/api/messages/' + id
幸运的是在ES6中我们有了新语法,在反引号包裹的字符串中,使用${NAME}语法来表示模板字符:
var name = `Your name is ${first} ${last}`
var url = `http://localhost:3000/api/messages/${id}`
3. ES6中的多行字符串
另一个好吃的语法糖就是多行字符串,以前我们的实现是像这样的:
var roadPoem = 'Then took the other, as just as fair,nt'
+ 'And having perhaps the better claimnt'
+ 'Because it was grassy and wanted wear,nt'
+ 'Though as for that the passing therent'
+ 'Had worn them really about the same,nt'
var fourAgreements = 'You have the right to be you.n
You can only be you when you do your best.'
但是在ES6中,只要充分利用反引号。
var roadPoem = `Then took the other, as just as fair,
And having perhaps the better claim
Because it was grassy and wanted wear,
Though as for that the passing there
Had worn them really about the same,`
var fourAgreements = `You have the right to be you.
You can only be you when you do your best.`
4. ES6中的拆包表达式
拆包可能是一个比较难理解的概念,因为这里面真的是有魔法发生。假如说你有一个简单的赋值表达式,把对象中的house
的mouse
赋值为house
和mouse
的变量。
var data = $('body').data(), // 假设data中有mouse和house的值
house = data.house,
mouse = data.mouse
另一个拆包的实例(Node.js):
var jsonMiddleware = require('body-parser').json
var body = req.body, // body中有用户名和密码值
username = body.username,
password = body.password
但是在ES6中我们可以用以下语句替换:
var { house, mouse} = $('body').data() // 我们会拿到house和mouse的值的
var {jsonMiddleware} = require('body-parser')
var {username, password} = req.body
甚至在数组中也能用,简直疯狂!
var [col1, col2] = $('.column'),
[line1, line2, line3, , line5] = file.split('n')
习惯拆包语法可能需要一些时间,但是这绝对是糖衣炮弹
5.块级作用域的let
和const
你可能早就听过对ES6中的let
那些奇怪的传说,我记得我第一次到伦敦时为那些TO LET牌子感到非常困惑。但是ES6中的let
和出租无关,这不算是语法糖,它很复杂。let
是一个更新的var
,可以让你把变量作用域限制在当前块里。我们用{}
来定义块,但是在ES5中这些花括号起不到任何作用。
function calculateTotalAmount (vip) {
var amount = 0
if (vip) {
var amount = 1
}
{ // 让块来的更疯狂
var amount = 100
{
var amount = 1000
}
}
return amount
}
console.log(calculateTotalAmount(true))
运行结果将会是1000
。天啊!这是多大的一个Bug。在ES6中,我们用let
来限制变量作用域为函数内。
function calculateTotalAmount (vip) {
var amount = 0 // 或许应该用let, 但你可以混用
if (vip) {
let amount = 1 // 第一个数量为 0
}
{ // 更多的块
let amount = 100 // 第一个数量为 0
{
let amount = 1000 // 第一个数量为 0
}
}
return amount
}
console.log(calculateTotalAmount(true))
运行结果是0
,因为在if
块中也有let
。如果什么都没有的话(amount=1
),那么结果将会是1
。
说到const
,事情就简单多了。他仅仅产生是一个不可变的变量,并且他的作用域也像let
一样只有块级。为了演示,这里有定义了一堆常量,并且由于作用域的原因,这些定义都是有效的。
function calculateTotalAmount (vip) {
const amount = 0
if (vip) {
const amount = 1
}
{ // 更多的块
const amount = 100
{
const amount = 1000
}
}
return amount
}
console.log(calculateTotalAmount(true))
依我愚见,let
和const
让这门语言变得更加复杂,没有这些的时候我们只有一条路可以走,但是现在可以要考虑更多的情景。;-(
6. ES6中的类
如果你喜欢面向对象编程,那么你会特别喜欢这个特性。他让你编写和继承类时就跟在Facebook上发一个评论这么简单。
在ES5中,因为没有class
关键字(但它是毫无作用的保留字),类的创建和使用是让人十分痛苦的事情。更惨的是,很多伪类的实现像pseude-classical, classical, functional让人越来越摸不着头脑,为JavaScript的信仰战争火上浇油。
我不会给你展示在ES5中怎么去编写一个类(是啦是啦从对象可以衍生出来其他的类和对象),因为有太多方法去完成。我们直接看ES6的示例,告诉你ES6的类会用prototype
来实现而不是function
。现在有一个baseModel
类,其中我们可以定义构造函数和getName()
方法。
class baseModel {
constructor(options = {}, data = []) { // class constructor
this.name = 'Base'
this.url = 'http://azat.co/api'
this.data = data
this.options = options
}
getName() { // class method
console.log(`Class name: ${this.name}`)
}
}
注意到我给options
和data
用了默认参数,而且方法名再也不用加上function
或者:
了。还有一个很大的区别,你不能像构造函数里面一样向this.Name
指派值。怎么说呢,和函数
有相同缩进的代码里,你不能向name
赋值。如果有这个需要的话,在构造函数里面完成。
使用NAME extends PARENT_NAME
语法,AccountModel
从baseModel
继承而来。
class AccountModel extends baseModel {
constructor(options, data) {
调用父类构造函数时,只需带上参数轻松的调用super()
方法。
super({private: true}, ['32113123123', '524214691']) //call the parent method with super
this.name = 'Account Model'
this.url +='/accounts/'
}
想要高级一点的话,你可以像这样弄一个getter
方法,这样accountsData
就会变成一个属性。
get accountsData() { // 返回计算后的数据
// ... make XHR
return this.data
}
}
现在你要怎么用这个魔咒,很简单,就跟让三岁小孩相信圣诞老人存在一样。
let accounts = new AccountModel(5)
accounts.getName()
console.log('Data is %s', accounts.accountsData)
如果好奇输出结果的话:
Class name: Account Model
Data is 32113123123,524214691
7. ES6中的模块化
你可能知道,ES6之前JavaScript并没有对模块化有过原生的支持,人们想出来AMD
,RequireJS
,CommenJS
等等,现在终于有import
和export
运算符来实现了。
ES5中你会用script
标签和IIFE(立即执行函数)
,或者是其他的像AMD
之类的库,但是ES6中你可以用export
来暴露你的类。我是喜欢Node.js的人,所以我用和Node.js语法一样的CommonJS
,然后用Browserfy来浏览器化。现在我们有一个port
变量和getAccounts
方法,在ES5中:
module.exports = {
port: 3000,
getAccounts: function() {
...
}
}
在ES5的main.js
中,用require('模块')
来导入:
var service = require('module.js')
console.log(service.port) // 3000
但是在ES6中,我们用export
和import
。比如这是ES6中的module.js
文件:
export var port = 3000
export function getAccounts(url) {
...
}
在需要引入的main.js
文件中,可以用import {名称} from '模块'
语法:
import {port, getAccounts} from 'module'
console.log(port) // 3000
或者就直接在main.js
中引入所有的变量:
import * as service from 'module'
console.log(service.port) // 3000
个人来说,我觉得这样的模块化有些搞不懂。确实,这样会更传神一些 。但是Node.js中的模块不会马上就改过来,浏览器和服务器的代码最好是用同样的标准,所以目前我还是会坚持CommonJS/Node.js
的方式。
目前来说浏览器对ES6的支持还遥遥无期(本文写作时),所以你需要一些像jspm这样的工具来用ES6的模块。
想要了解更多ES6中的模块化和例子的话,来看这篇文章,不管怎么说,写现代化的JavaScript吧!