使用ES6进行开发的思考
ECMAScript6已经于近日进入了RC阶段,而早在其处于社区讨论时,我就开始一直在尝试使用ES6进行开发的方案。在Babel推出后,基于ES6的开发也有了具体可执行的解决方案,无论是Build还是Debug都能得到很好的支持。
而在有了充足的环境、工具之后,我们面临的是对ES6众多新特性的选择和分析,以便选取一个最佳的子集,让我们可以享受ES6带来的便利(减少代码量、提高可读性等)的同时,也可以顺利运行于当前以ES3-ES5为主的浏览器环境中。
经过分析后,本文试图对ES6各个特性得出是否适合应用的初步结论,并一一解释其使用场景。ES6的特性列表选自es6features。
- ★★★ 推荐使用
- ★★ 有考虑地使用
- ★ 慎重地使用
- ☆ 不使用
特性 | 推荐程度 |
---|---|
arrows | ★★★ |
classes | ★★★ |
enhanced object literals | ★★★ |
template strings | ★★★ |
destructuring | ★★ |
default + rest + spread | ★★★ |
let + const | ★★★ |
iterators + for..of | ★★ |
generators | ★ |
unicode | ☆ |
modules | ★★ |
module loaders | ☆ |
map + set + weakmap + weakset | ★★ |
proxies | ☆ |
symbols | ★ |
subclassable built-ins | ☆ |
promises | ★★★ |
math + number + string + array + object APIs | ★★★ |
binary and octal literals | ★ |
reflect api | ☆ |
tail calls | ★★ |
接下来我们以上特性挨个进行介绍。需要关注一点:如果你不想使用shim库(如Babel的browser-polyfill.js
和generatorsRuntime.js
)或者想使用尽可能少的helper(Babel的externalHelpers
配置),那么需要按你的需求进一步缩减可使用的ES6特性,如Map
、Set
这些就不应该使用。
语法增强类
Arrow function
Arrow functions是ES6在语法上提供的一个很好的特性,其特点有:
- 语法更为简洁了。
- 文法上的固定
this
对象。
我们鼓励在可用的场景下使用Arrow functions,并以此代替原有的function
关键字。
当然Arrow functions并不是全能的,在一些特别的场景下并不十分适用,最为典型的是Arrow functions无法提供函数名称,因此做递归并不方便。虽然可以使用Y combinator来实现函数式的递归,但其可读性会有比较大的损失。
配合后文会提到的对象字面量增强,现在我们定义方法/函数会有多种方式,建议执行以下规范:
所有的Arrow functions的参数均使用括号
()
包裹,即便只有一个参数:// Good
let foo = (x) => x + 1; // Bad
let foo = x => x + 1;定义函数尽量使用Arrow functions,而不是
function
关键字:// Good
let foo = () => {
// code
}; // Bad
function foo() {
// code
} // Bad
let foo = function () {
// code
}除非当前场景不合适使用Arrow functions,如函数表达式需要自递归、需要运行时可变的
this
对象等。对于对象、类中的方法,使用增强的对象字面量:
// Good
let foo = {
bar() {
// code
}
}; // Bad
let foo = {
bar: () => {
// code
}
}; // Bad
let foo = {
bar: function () {
// code
}
};
增强的对象字面量
对象字面量的增强主要体现在3个方面:
可在对象中直接定义方法
let foo = { |
我们推荐使用这种方式定义方法。
可使用通过计算得出的键值
let MY_KEY = 'bar'; |
我们推荐在需要的时候使用计算得出的键值,以便在一个语句中完成整个对象的声明。
与当前Scope中同名变量的简写
let bar = 'bar'; |
我们并不推荐这样的用法,这对可读性并没有什么帮助。
模板字符串
模板字符串的主要作用有2个:
多行字符串
let html = |
从上面的代码中可以看出,实际使用多行字符串时,对齐是个比较麻烦的事。如果let html
这一行本身又有缩进,那么会让代码更为难受一些。
因此我们不推荐使用多行字符串,必要时还是可以使用数组和join('')
配合,而生成HTML的场景我们应该尽量使用模板引擎。
字符串变量替换
let message = `Hello ${name}, it's ${time} now`; |
这是一个非常方便的功能,我们鼓励使用。但需要注意这些变量并不会被HTML转义,所以在需要HTML转义的场景,还是乖乖使用模板引擎或者其它的模板函数。
解构
解构(原谅我没什么好的翻译)是个比较复杂的语法,比如:
let [foo, bar] = [1, 2]; |
还可以有更复杂的,具体可以参考MDN的文档。
对于这样一个复杂且多变的语法,我们要有选择地使用,建议遵循以下原则:
- 不要一次通过解构定义过多的变量,建议不要超过5个。
- 谨慎在解构中使用“剩余”功能,即
let [foo, bar, ...rest] = getValue()
这种方式。 - 不要在对象解构中使用过深层级,建议不要超过2层。
函数参数增强
ES6为函数参数提供了默认值、剩余参数等功能,同时在调用函数时允许将数组展开为参数,如:
var foo = (x = 1) => x + 1; |
我们鼓励使用这些特性让函数的声明和调用变得更为简洁,但有一些细节需要注意:
- 在使用默认参数时,如果参数默认值是固定且不会修改的,建议使用一个常量来作为默认值,避免每一次生成的开销。
- 不要对
arguments
对象使用展开运算,这不是一个数组。
关键字类
let和const
这是2个用来定义变量的关键字,众所周知的,let
表示块作用域的变量,而const
表示常量。
需要注意的是,const
仅表示这个变量不能被再将赋值,但并不表示变量是对象、数组时其内容不能改变。如果需要一个不能改变内容的对象、数组,使用Object.freeze
方法定义一个真正的常量:
const DEFAULT_OPTIONS = Object.freeze({id: 0, name: 'unknown'}); |
不过如果你在程序中能控制不修改对象的话,这并不具备什么意义,Object.freeze
是否会引起执行引擎的进一步优化也尚未得到证实。
我们推荐使用let
全面替代var
。同时建议仅在逻辑上是常量的情况下使用const
,不要任何不会被二次赋值的场景均使用const
。
迭代器和for..of
迭代器是个好东西,至少我们可以很简单地遍历数组了:
for (let item in array) { |
但是迭代器本身存在一些细微的缺点:
- 性能稍微差了一些,对于数组来说大致与
Array.prototype.forEach
相当,比不过原生的for
循环。 - 不能在循环体中得到索引
i
的值,因此如果需要索引则只能用原生的for
循环。 - 判断一个对象是否可迭代比较烦人,没有原生方法提供,需要自行使用
typeof o[Symbol.iterator] === 'function'
判断。
对于迭代器,我们鼓励使用并代替原生for
循环,且推荐关注以下原则:
- 对于仅一个语句的循环操作,建议使用
forEach
方法,配合Arrow functions可非常简单地在一行写下循环逻辑。 - 对于多个语句的循环操作,建议使用
for..of
循环。 - 对于循环的场景,需要注意非数组但可迭代的对象,如
Map
和Set
等,因此除arguments
这类对象外,均建议直接判断是否可迭代,而不是length
属性。
生成器
生成器(Generators)也是一个比较复杂的功能,具体可以参考MDN的文档。
对于生成器,我的建议是非常谨慎地使用,理由如下:
- 生成器不是用来写异步的,虽然他确实有这样一个效果,但这仅仅是一种Hack。异步在未来一定是属于
async
和await
这两个关键字的,但太多人眼里生成器就是写异步用的,这会导致滥用。 - 生成器经过Babel转换后生成的代码较多,同时还需要
generatorsRuntime
库的支持,成本较高。 - 我们实际写应用的大部分场景下暂时用不到。
生成器最典型的应用可以参考C#的LINQ获取一些经验,将对一个数组的多次操作合并为一个循环是其最大的贡献。
模块和模块加载器
ES6终于在语言层面上定义了模块的语法,但这并不代表我们现在可以使用ES6的模块,因为实际在ES6定稿的时候,它把模块加载器的规范给移除了。因此我们现在有的仅仅是一个模块的import
和export
语法,但具体如“模块名如何对应到URL”、“如何异步/同步加载模块”、“如何按需加载模块”等这些均没有明确的定义。
因此,在模块这一块,我们的建议是使用标准语法书写模块,但使用AMD作为运行时模块解决方案,其特点有:
- 保持使用
import
和export
进行模块的引入和定义,可以安全地使用命名export
和默认export
。 - 在使用Babel转换时,配置
modules: 'amd'
转换为AMD的模块定义。 - 假定模块的URL解析是AMD的标准,
import
对应的模块名均以AMD标准书写。 - 不要依赖
SystemJS
这样的ES6模块加载器。
这虽然很可能导致真正模块加载器规范定型后,我们的import
模块路径是不规范的。但出于ES6的模块不配合HTTP/2简直没法完的考虑,AMD一定很长一段时间内持续存在,我们的应用基本上都是等不到HTTP/2实际可用的日子的,所以无需担心。
类型增强类
Unicode支持
这个东西基本没什么影响,我们很少遇到这些情况且已经习惯了这些情况,所以可以认为这个特性不存在而继续开发。
Map和Set
两个非常有用的类型,但对不少开发者来说,会困惑于其跟普通对象的区别,毕竟我们已经拿普通对象当Map
和Set
玩了这么多年了,也很少自己写一个类型出来。
对于此,我们的建议是:
- 当你的元素或者键值有可能不是字符串时,无条件地使用
Map
和Set
。 - 有移除操作的需求时,使用
Map
和Set
。 - 当仅需要一个不可重复的集合时,使用
Set
优先于普通对象,而不要使用{foo: true}
这样的对象。 - 当需要遍历功能时,使用
Map
和Set
,因为其可以简单地使用for..of
进行遍历。
因此,事实上仅有一种情况我们会使用普通的对象,即使用普通对象来表达一个仅有增量Map
,且这个Map
的键值是字符串。
另外,WeakMap
和WeakSet
是没有办法模拟实现的,因此不要使用。
Proxy
这不是一个可以模拟实现的功能,没法用,因此不要使用Proxy。
Symbol
Symbol
最简单的解释是“可用于键值的对象”,最大的用处可能就是用来定义一些私有属性了。
我们建议谨慎使用Symbol
,如果你使用它来定义私有属性,那么请保持整个项目内是一致的,不要混用Symbol
和闭包定义私有属性等手段。
可继承的内置类型
按照ES6的规范,内置类型如Array
、Function
、Date
等都是可以继承且没有什么坑的。但是我们的代码要跑在ES3-5的环境下,显然这一特性是不能享受的。
Promise
这个真没什么好说的,即便不是ES6,我们也已经满地用着Promise
了。
建议所有异步均使用Promise实现,以便在未来享受async
和await
关键字带来的便携性。
另外,虽然Babel可以转换async
和await
的代码,但不建议使用,因为转换出来的代码比较繁琐,且依赖于generatorsRuntime
。
各内置类型的方法增强
如Array.from
、String.prototype.repeat
等,这些方法都可以通过shim库支持,因此放心使用即可。
二进制和八进制数字字面量
这个特性基本上是留给算法一族用的,因此我们的建议是除非数字本身在二/八进制下才有含义,否则不要使用。
反射API
Reflect
对象是ES6提供的反射对象,但其实没有什么方法是必要的。
其中的delete(name)
和has(name)
方法相当于delete
和in
运算符,而defineProperty
等在Object
上本身就有一套了,因此不建议使用该对象。
尾递归
当作不存在就好了……
转:http://efe.baidu.com/blog/es6-develop-overview/
使用ES6进行开发的思考的更多相关文章
- ES6的开发环境搭建
在搭建es6开发环境之前,先简单介绍一下es6. ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了.它的目标,是使得 Java ...
- 从无到有实现搭建vue+ElementUI+less+ES6的开发环境并进行简单的开发的项目
项目简介:该项目是基于日常计算宿舍水电煤气费的需求写的,旨在从无到有实现搭建vue+ElementUI+less+ES6的开发环境并进行简单的开发,使用webpack进行代码的编译.压缩和打包,并疏通 ...
- 一.ES6的开发环境搭建
前言: 现在的Chrome浏览器已经支持ES6了,但是有些低版本的浏览器还是不支持ES6的语法,这就需要我们把ES6的语法自动的转变成ES5的语法.Webpack是有自动编译转换能力的,除了Webpa ...
- 使用Vue2+webpack+Es6快速开发一个移动端项目,封装属于自己的jsonpAPI和手势响应式组件
导语 最近看到不少使用vue制作的音乐播放器,挺好玩的,本来工作中也经常使用Vue,一起交流学习,好的话点个star哦 本项目特点如下 : 1. 原生js封装自己的跨域请求函数,支持promise调用 ...
- J2EE学习从菜鸟变大鸟之八 企业级项目开发的思考
什么是企业级项目开发 "企业级项目".企业级项目开发,Java也是企业级项目开发,这个我们到处说.听,每天被我们挂在嘴边,可是到底什么项目才算是"企业级"?自己 ...
- 开始学习es6(一) 搭建个es6的开发环境
1.开始学习es6 如果想在浏览器跑es6 需要给es6个环境 因为一直用vue-cli全家桶 这样虽然方便 但如果用es6需要跑起个vue全家桶 于是想到可以用gulp搭建个开发环境 首先需要1. ...
- 关于WEB前端开发的思考与感悟
万事开头难. 当我想要认真写一篇文章向大家分享我对前端的认识与感悟的时候,突然就深刻的体会到了这句话确实太有道理了. 最近几年对于web前端的传闻很多,比如人才稀缺,简单易学,待遇丰厚,整体势头发展良 ...
- WEB前端开发的思考与感悟
当我想要认真写一篇文章向大家分享我对前端的认识与感悟的时候,突然就深刻的体会到了这句话确实太有道理了. 最近几年对于web前端的传闻很多,比如人才稀缺,简单易学,待遇丰厚,整体势头发展良好等等.遇到过 ...
- C语言开发的思考
维护过十万行代码的通信协议,自己从头开始开发过几万行的代码,步骤: 1.移植性.为移植性对数据类型做重新定义. 2.内存计数.不要直接使用malloc和free,而是给所有类型的内存申请定义类型,并计 ...
随机推荐
- 现有有N个学生的数据记录,每个记录包括学号、姓名、三科成绩。 编写一个函数input,用来输入一个学生的数据记录。 编写一个函数print,打印一个学生的数据记录。 在主函数调用这两个函数,读取N条记录输入,再按要求输出。 N<100
#include <iostream> using namespace std; struct student {char num[100]; char name[100]; int ...
- ECSTORE关于MONGODB安装
1.安装mongodb wget http://www.phpwindow.com/linux/mongodb-linux-x86_64-2.2.1.tgz tar zxvf mongodb-linu ...
- python学习第十天 -- 函数
稍微学过其他编程语言的人都应该了解函数的概念.在这里就不做过多的介绍. Python内置了很多有用的函数,我们可以也直接调用. 可以直接从Python的官方网站查看文档: http://docs.py ...
- controller 和 指令 通讯方法
在 angular 中我们经常会使用多个 controller 和 指令 他们拥有各自的 $scope , 这就产生了跨$scope调用的问题. 有几种常见的方法来可以使用. 方法一 : 指令 req ...
- Qt浅谈之二十App自动重启及关闭子窗口
一.简介 最近因项目需求,Qt程序一旦检测到错误,要重新启动,自己是每次关闭主窗口的所有子窗口但有些模态框会出现问题,因此从网上总结了一些知识点,以备以后的应用. 二.详解 1.Qt结构 int ma ...
- Linq to OBJECT延时标准查询操作符
1.Where 操作符用于限定输入集合中的元素,将符合条件的元素组织声称一个序列结果.2.Select 操作符用于根据输入序列中的元素创建相应的输出序列中的元素,输出序列中的元素类型可以与输入序列中 ...
- C#中使用命名管道进行进程通信的实例
原文:C#中使用命名管道进行进程通信的实例 1 新建解决方案NamedPipeExample 在解决方案下面新建两个项目:Client和Server,两者的输出类型均为"Windows 应用 ...
- 有关WCF的契约问题
WCF中的契约包括4种 数据契约 DataContract ->DataMember 服务契约 ServiceContract-> OperactionContract 消息契约 Mess ...
- SOSP 文档 - Windows Azure 存储:具有强一致性的高可用性云存储服务
之前,我们在第 23 届 ACM操作系统原理研讨会 (SOSP)上发布了一篇文章,其中介绍了 Windows Azure存储的内部详细信息. 您可以在此处找到该文章.此次大会还发布了一段视频讲话( ...
- iOS 9之New System Fonts(San Francisco 字体)
金田 此次苹果发布的iOS 9系统测试版目前已经开放下载,新系统将弃用Helvetica字体,改用了San Francisco字体, 包括系统菜单.App名称等各个部分. 最初San Francisc ...