在讲 ES 2015 新语法之前,先来说一下为什么叫 ES。JavaScript 是这门语言的名称,它有一个为它制定标准化的组织 European Computer Manufacturers Association,直译就是欧洲计算机制造商协会。这个 ECMA 制定的 JavaScript 的实现标准,被称为 ECMAScript,不同组织写出来的 JavaScript 语言都要遵守这个 ECMAScript 标准,所以就简写为 ES+版本号。

这套 ES 标准在2015年之前最高的版本是5.1,也是唯一一个需要大家注意的版本:尽管各个流浏览器实现的 ES 新语法都有差异,但5.1版本是目前各大主流浏览器都支持的。这里再介绍一下传说中的 Babel.js 项目,它的目的很简单,把新语法翻译成老标准的语法。最主要的应用,就是把你写的 ES 201x 的语法翻译成 ES5.1,这样各个浏览器都是支持的。

在2015年的时候,ES6 正式发布,也很自然按照年份被称为 ES 2015。之后 ES 每年都发布一个版本,今年也就是2018年的草案也已经在年初发布了,从6开始今年该到版本9了但是不好记,所以大家都喜欢用 201x 来称呼。虽然语法是归在不同版本内的,但是各家 JS 的实现进度不同。你问一个语法具体是哪个版本实现的,估计10个人里有9个说不清楚,反正不是5.1的语法,所以大家也不区分了,直接都叫 ES 201x。

已经出来了好几年了,所以各种介绍的文章也很全面,我就不复制粘贴又臭又长了。在这里向大家推荐几个学习语法的英文网站,我就是从 babel 和 es6-features.org 这两个网站学习的:

https://babeljs.io/learn-es2015/

http://es6-features.org/

https://css-tricks.com/lets-learn-es2015/

中文的话,可以看这个网站:

http://es6.ruanyifeng.com

另外呢,MDN( https://developer.mozilla.org ) 上对于这些语法的介绍是很全面的,中文英文也都有。

那么接下来呢,我打算讲一讲这些新语法都解决了哪些问题,你应该怎么使用它,这是一般介绍语法的文章不会介绍的。提前说明一下,我个人平时都在用 airbnb 的代码风格,所以这些代码都会延用它家的风格来写。

一、const 与 let

首先要说的是,由于 var 的问题很多,新语法中永远不要用 var。它有的主要问题作用域是整个函数(function)而不是语法块(block),导致的最大问题是会让 closure 出现“bug”。而且这个“bug”还很经典,出现在许多著名语言中,其中也包括了

脚本界的老二 Python。构造这个 bug 的方法很简单:

 {
const funcs = [];
for (var i = 0; i < 5; i++) {
funcs.push(() => i);
}
funcs.map(fn => fn());
}

把上面的代码粘贴到浏览器的 console 里面,结果是5个5,而不是 [0, 1, 2, 3, 4],惊不惊喜,意不意外?虽然把上面的 var 换成 let 就成功的解决了这个问题,但按照现在 JS 倾侧 FP 而不鼓励使用 for 的趋势,下面的方法才是正确的使用姿势:

 import { times } from 'lodash';

 const funcs = times(5, i => () => i);

lodash 是一个著名而且非常流行的 JS 库,以后会有专门的文章介绍它。下面再给出其它语言生成这个 clusure 数组的正确投资,用 Python 举例:

 funcs = []
for i in range(5):
funcs.append((lambda x: lambda: x)(i))
[fn() for fn in funcs]

再嵌一层函数来返回需要生成函数的函数,然后再把参数传过去。

那么 const 呢,我在另外一个扯一扯编译语言的系列中已经提过,能用 const 就不要用 let。如果你使用了 eslint 的话,只赋值过一次的 let 变量会被提示应该换成 const。

总结下来,就是用 const 代替 var,const 实在解决不了的情况,再用 let。不要觉得 const 多敲俩字母就不爱用,早几年还能看到 let 满天飞没有 const 的项目,现在一个项目里 let 出现的少才说明作者的水平高。一旦用了 var 你就是菜B一个,所以千万不要用。

二、=> 箭头函数(Arrow Function)

简单来讲是 function () {} 的简写形式,括号和参数列表写在 => 前面,大括号和函数体写在 => 后面,但是有3个非常重要的区别:

  1. function 的形式有两组重要的变量,一个是 arguments,主要代表一个包含所有实参的数组,另外一组是对象的上下文环境,主要包括 this、super。箭头函数本身是没有 this、super、arguments 这几个变量的。
  2. 如果箭头函数的函数体只返回一个表达式,也就是 () => { return EXPRESSION; },可以省略 { return },也就变成了 () => EXPRESSION
  3. 当箭头函数的参数只有一个时,可以省略参数两边的括号。上面那段代码中,就是因为外层的函数只有一个参数,我把 (i) => () => i 简写成了上面的形式。

最后一点并不重要,但是 airbnb 的代码风格要求在只有一个参数时不使用括号,所以我在这里专门提到了,但前面两点都有值得说的地方。

第一条中不再带 this 等上下文变量,是为了解决之前常常被诟病的搞不清当前 this 是啥的问题。JS 的对象模型是非主流的 prototype(原型)模型,在调用对象函数时,实际上使用的是类似 func.apply(this, arguments) 或者 func.call(this, ...arguments) 来实现的。所以当对象成员函数里面又套了一层 function 的时候,由于在内层函数声明的时候 this 并没有关联任何上下文变量,而导致在内层函数中 this 使用时并不是该对象,经常会导致试图调用 undefined 的成员函数的问题。而且因为这个模型实在是太非主流了,所以大家经常会忘掉甚至搞不清。所以这个语法在很大程度上就是为了解决 this 的问题。

第二条也会带来一个问题,很多时候我们想返回一个 Object,比如 { foo: 123, bar: 'baz' },但是 {} 这个东西又是函数体。很遗憾编译器没那么聪明,当你写 () => { foo: 123, bar: 'baz' } 的时候,会报语法错误。解决的办法也很简单,() 虽然套在表达式的外面它还是一个表达式,所以 () => ({ foo: 123, bar: 'baz' }) 这种写法就没问题了。在 FP 流行的今天,这个技巧的使用真的是十分常见的,所以请养成想要返回 Object 时,直接先敲 ({}) 的习惯。

三、模板字符串(Template String)

Babel 的文档里面说,“This is similar to string interpolation features in Perl, Python and more.”,然而我并不觉得它跟 string interpolation 有什么本质上的不同。这里介绍一个技巧,如果你想 google 其它语言的这个语法的话,比如 Kotlin,那么你应该用“string interpolation kotlin”作关键字,搜 template 可能不一定是你想要的结果,但 interpolation 一定能搜到。

这个语法本身已经是现在语言的标配了,用标准键盘左上角的 `` 来包裹字符,可以跨行,里面全部的 ${EXPRESSION} 都会变成 EXPRESSION.toString() 插入到字符串中。

但是 JS 的这个语法还有一个神奇的用法,废话不多说直接上代码:

 function test() { return JSON.stringify(arguments); }
test`foo${123}bar${456+789}baz`

你将会看到这样的结果:{"0":["foo","bar","baz"],"1":123,"2":1245} 。第一个参数是正常的字符串部分,按照插入表达式的地方给切开了,剩下的参数则是其它表达式的值。虽然你不太可能会有机会需要用这语法来实现自己的库的功能,但还是有挺大的机会碰到第三方库提供这样的“语法支持”,比如 React 社区一些 CSS 库。当你看到的时候,就不会觉得奇怪,到底人家的库是怎么写的了。

四、模块(Module)

作为一门现代语言,没有模块化的设计是不可能达到工程级的使用的。过去我们在使用 JS 的时候,都是在 HTML 里导入 JavaScript 库比如 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>。但这么做会带来一个问题就是可能会污染全局变量,一个现实的结果就是,假如有两个库都用了同一个全局变量名,那么你就只能很小心的在引用两个库的中间插入一段代码,重命名其中一个全局变量的名称。另外一个问题是,当一个库需要使用另外一个库的时候,必须严格遵守一定的顺序。

模块化之后,带来了两个好处,一个是可以自由的在本模块中自由的命名,另一个是使用 webpack 等工具打包时,可以只打包使用到的代码,从而减小需要发布的 JS 文件大小,节省网络传输时间加快页面加载速度。

遗憾的是,由于 JS 的模块化并没有统一的标准,导致出现了各种不同的加载方式。不过由于 webpack 和 babel 的存在,在写前端代码时,你只要使用 export/import 这一套语法就够了。但如果写 Node 代码,而你又不想使用 Babel 的话,那就得注意一下,由于打包方式不同,一些在导入 default 时会要求 require(XXX).default,比如 redux-thunk。不过这种情况一般也都是前端库的代码,如果纯后端的话应该也不太需要担心。

五、二进制与八进制数字(Binary & Octal Literals)

这个语法也挺简单的,跟16进制类似,0b 或者 0B 是2进制的前缀,用字母 O 替换 X 就是8进制的前缀。但是有一点需要注意的地方,你自己写代码的时候用用可以,但是不要指望 parseInt 可以像对十六进制一样起作用。而像 isNaN、Number 之类的,跟浏览器本身的支持也有关,就算你上了 polyfill 也不一定会支持。当然大家会用这个语法的概率也不大。

六、其他

关于 Symbol(符号)、Set、Map、WeekSet、WeekMap,个人感觉不使用其实影响也不大,而且 polyfill 也不能做到完全支持,做前端就不要考虑了。for ... of 的语法意义也不大,毕竟现在主流已经不推荐写 for 了。iterator 本身没有 Generator 好用,polyfill 支持也有限,所以也没啥意义。剩下的 API 变化也没什么值得说的,前端也只要注意加个 babel-polyfill 之类的就够了。

Proxy、Reflect、Decorator 算是 meta-programming 的内容,需要读我的文章想来水平还不到有机会写神奇功能的水平。如果想实现一些 fancy 的功能,这几个东西还是很有用的。举个例子,比如你想监视(observe)对象成员值的变化,老的做法你就得跑过去,获取这个对象当前所有的属性,然后再都给封装一遍,就算这样如果人家再加了个新成员变量你还是没办法知道。上了 Proxy 你就不用那么麻烦了,所有的操作都会在你的 proxy handler 里面过一遍,实现起来就简单多了。

其它的语法,Promise、async/await、Generator 会在异步里面讲,函数的变化、class、Rest/Spread、Destructing 相关性比较高也会放在同一个章节里面讲。

最新文章

  1. 【第三课】WEBIX 入门自学-Hello World
  2. 常用的CentOS 7系统yum源集合
  3. 正在使用广告标识符 (IDFA)
  4. 怎样将BigDecimal转换成Int
  5. 通过 XML HTTP 把文本文件载入 HTML 元素
  6. Asynctask的使用及理解
  7. jQuery选择器之动态列表显示Demo
  8. LeetCode Contains Duplicate II (判断重复元素)
  9. Python 列表实现字典的get功能
  10. 《JavaScript 闯关记》之对象
  11. 从C#到TypeScript - Promise
  12. 计算机原码、补码、反码与java移位运算符(&lt;&lt;/&gt;&gt;/&gt;&gt;&gt;)
  13. layui 弹出框改变按钮颜色样式 自定义皮肤
  14. Fidder 请求信息颜色的含义
  15. 机器学习(Machine Learning)算法总结-决策树
  16. 【UFUN开发板评测】小巧而不失精致,简单而不失内涵——uFun开发板开箱爆照
  17. Net SMTP QQ 发送邮件
  18. LeetCode刷题 Flood Fill 洪水填充问题
  19. Sharing Code Between Silverlight and WPF
  20. DataTableExtensions

热门文章

  1. Java最佳实战
  2. EF Core 2.0中怎么用DB First通过数据库来生成实体
  3. std::tuple作为参数invoke调用函数
  4. Autowire
  5. flume从log4j收集日志输出到kafka
  6. js事件委托篇(附js一般写法和js、jq事件委托写法)
  7. python安装包下载慢的问题 | Python
  8. [BZOJ4010]菜肴制作
  9. 使用@Named注解绑定多个实现(java,scala)
  10. [OpenCV]OpenCV常用语法函数与坑点