在讲 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 相关性比较高也会放在同一个章节里面讲。

Node.js 全栈开发(二)——ES 201x 新语法的使用之基础篇的更多相关文章

  1. Node.js 全栈开发(一)——Web 开发技术演化

    这些年一直不断接触学习 Node 技术栈,个人的技术开发学习兴趣也越来越倾向 node 流.也许是由于英语的关系,也许是因为墙增加了学习国外一手资料的难度,加上现在流行的 web 开发技术并不太容易上 ...

  2. Flask Vue.js全栈开发

    Flask Vue.js全栈开发的 最新完整代码 及使用方式 本系列的最新代码及使用方式将持续更新到: http://www.madmalls.com/blog/post/latest-code/ 1 ...

  3. Python 全栈开发二 python基础 字符串 字典 集合

    一.字符串 1,在python中,字符串是最为常见的数据类型,一般情况下用引号来创建字符串. >>ch = "wallace" >>ch1 = 'walla ...

  4. python全栈开发从入门到放弃之socket网络编程基础

    网络编程基础 一 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务 ...

  5. PHP全栈开发(五):PHP学习(1.基础语法)

    PHP脚本在服务器上执行,然后将纯HTML的结果返回给浏览器. 听上去很厉害的样子,所以说PHP是服务器端的语言啦.HTML才是前端啦. PHP文件的默认文件扩展名是".php" ...

  6. Python全栈开发【基础二】

    Python全栈开发[基础二] 本节内容: Python 运算符(算术运算.比较运算.赋值运算.逻辑运算.成员运算) 基本数据类型(数字.布尔值.字符串.列表.元组.字典) 其他(编码,range,f ...

  7. spring boot + vue + element-ui全栈开发入门——基于Electron桌面应用开发

     前言 Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库. Electron通过将Chromium和Node.js合并到同一个运行时环 ...

  8. CabloyJS全栈开发之旅(1):NodeJS后端编译打包全攻略

    背景 毋庸置疑,NodeJS全栈开发包括NodeJS在前端的应用,也包括NodeJS在后端的应用.CabloyJS前端采用Vue+Framework7,采用Webpack进行打包.CabloyJS后端 ...

  9. Python全栈开发【模块】

    Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...

随机推荐

  1. TOSCA自动化测试工具--怎么写自动化用例

    1.查看一下要测试的对象属性 2.

  2. 什么是Socket?简单点,通俗易懂的?

    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 建立网络通信连接至少要一对端口号(socket).socket本质是编程接口(API),对TCP/IP的封装 ...

  3. 阿里云ECS服务器磁盘挂载(转)

    买了阿里云的ECS云服务器,本机赠送20GB的磁盘,感觉不够用,又买了一块500GB的磁盘,本文就是记录怎么把这500GB的磁盘挂载上. 检查现在磁盘情况 我们可以看到买的那个500GB的磁盘没有出现 ...

  4. C++MFC之picture control控件铺满图片

    UpdateData(true); //更新路径公共变量     CString m_path = m_edit1.GetString();      if(m_path=="") ...

  5. C#创建类,方法,接口,字段 的 默认类型

    1.在namespace中的类.接口默认是internal类型的,也可以显示的定义为public类型2.在一个类里面,属性和方法默认是private的,可以显示的定义为public.private.p ...

  6. Java伙伴系统(模拟)

    参考:https://labrick.cc/2015/10/12/buddy-system-algorithm/ 代码过烂 不宜参考. output: [operating.entity.Heap@4 ...

  7. clientWidth offsetWidth scrollWidth

    网页可见区域宽: document.body.clientWidth;网页可见区域高: document.body.clientHeight;网页可见区域宽: document.body.offset ...

  8. 20145309《Java程序设计》第七周学习总结

    教材学习内容总结 第13章 时间与日期 13.1 认识时间与日期 13.1.1 时间的度量 格林威治时间(GMT) 世界时(UT) 国际原子时(TAI) 世界协调时间(UTC) Unix时间:Unix ...

  9. 关于js中对事件绑定与普通事件的理解

    普通事件指的是可以用来注册的事件: 事件绑定是指把事件注册到具体的元素之上. 通俗点说: 普通事件:给html元素添加一个特定的属性(如:onclick): 事件绑定:js代码中通过标记(id  ta ...

  10. openwrt的编译系统在哪里对程序进行开机自动启动配置

    答:在include/rootfs.mk里的宏prepare_rootfs中进行的