《如何学习和实践ES201X?》知乎 live 笔录
作者 王川川2017-09-25阅读 2888
本文为 100offer 发起的知乎 Live「如何学习和实践ES201X?」活动笔录。分享嘉宾为百姓网 前端工程师 贺师俊 (hax)。

大家好,我叫贺师俊,现在就职于百姓网。欢迎大家@我,我在微博上是johnhax、知乎上是贺师俊、Github上是hax。今天应100offer的邀请,跟大家一起讨论一下ES标准相关的内容。

一、为什么JavaScript为什么每年都有新标准?

我们知道的前年有ES2015,去年有ES2016,今年六月份发布的ES2017,明年还会有ES2018,以此类推。但是JavaScript以前并不是这样子的,大家知道ES2015其实就是ES6,之前迭代的版本是ES1,ES2,ES3,ES5,没有ES4。其中第一个版本是1997年发布的,ES3是一个重要的版本,是1999年发布的,ES5大概是2009年发布的,两个重要的版本ES3和ES5之间隔了十年,这就导致了很多问题,编程语言和软件、项目一样,都是需要进化和发展的,而JavaScript在长达10年的时间没有很好的进化。如果一个语言从一开始就设计的非常好,非常完备,可以说它基本不需要变化了,但是JS显然不是这样子的,从著名的"犀牛书"《JavaScript权威指南》和Douglas Crockford的《JavaScript语言精粹》两本宝典的厚度对比中就可以看得出来,JS语言还是有很多问题的。

二、为什么会造成在10年的时间里面都没有新的语言的标准?

  • 我们经常说的浏览器的发展对于语言的发展是一种拖累,因为大家知道如果浏览器不升级,在写代码的时候要考虑到浏览器的兼容性,也就没有办法使用最新的特性,这个问题也反映在ES5上面,前面讲过ES5是在2009年发布的,但是到2011年大多数的WEB开发者还是在用ES3在写程序,并没有用到ES5的新特性。据我所知司徒正美(钟钦成,著名的JavaScript专家,去哪儿网前端架构师,曾出版《JavaScript框架设计》一书)也参加了我的这次Live。他做了很多的框架,比方说 Avalon,最近又复刻了 React 的一个框架,它们有很多特点,包括支持IE6等老旧浏览器,大家有兴趣的可以去尝试一下。现在大部分的框架已经不支持IE6,IE8了,基本从 IE9 开始,更有甚者直接从 IE10 和 IE11 开始。但是往前推5,6年还不是这个样子的。所以这个一方面就影响了 JavaScript 语言的进化。
  • 在语言委员会中可能有些政治斗争的问题,ES4的死亡有些是因为技术原因,还有些是技术以外的原因,在这块就不过多涉及了。因为上述原因,所以每个大版本之间隔得时间会比较长,而且ES6(ES2015)加了非常多的新特性,例如Class、iterator、generator、Modules等这些都是新语言级别的特性,所以需要很长的时间来讨论和研发。在ES6(ES2015)之后,语言委员会也总结了,认为以后再推进语言的发展,最好不要像ES6(ES2015)那样,一次性加入那么多的特性,这样做会有很大的困难,需要考虑兼容,JS是用在WEB上的,所以对兼容性的要求就更高。因此委员会决定从ES6(ES2015)之后,改进之前的推进标准的方法,以前的方法是:大家一起讨论要加入一些什么特性,全部讨论完之后,一次性加入进去;以后不会再这么做了,而是单个特性一个一个去加,每个特性单独提案,再根据每个特性自己的发展是不是成熟,浏览器的实现是不是跟进了,再来决定这个特性是不是能够加入到下一年的标准里。基于这样的改变,我们现在的标准就变成了ES2015,2016,2017,以年份来命名的版本号。当然ES7,ES8,ES9也可以继续用这个称呼,因为数字6、7、8、9实际上是标准的版本号,这个标准实际上叫 ECMAScript,也就是 ECMA 标准化组织所制定的标准,每个标准上面都有一个 edition,也就是说这个标准可以不断的有新的版本,一个完整的ES6称呼应该是 ECMAScript edition 6,你可以用数字编号,但是用年份会更加清楚。

三、每年的 ECMAScript 201X 标准又是如何制定和发布的?

现在每一年的标准是在ES6(ES2015)的基础上的更新,比方说ES2017就是对ES2016的更新,ES2016就是对ES2015的更新,它的更新把当年已经完全成熟并且决定可以进入标准的新的特性提案合并提交到标准文本里面,到下一年发布出来。现在是在每年的六、七月份发布正式标准,实际上到底哪些特性可以进入下一年的标准很早就确定了,基本在当年的一月份就已经确定了,如果说一个提案到一月份都没确定进入标准,就不可能进入到当年的标准,需要放到下一年的标准里面。

四、为什么要学习和实践 ES201X?我能不学(用)它们而继续只写 ES5(ES3)吗?

首先JavaScript不会去破坏以前代码的兼容性,以前代码跑的结果基本上是不会变的,除非是在非常个别的地方,而且这个地方不仅经过委员会讨论,数据也表明整个互联网都没有人会写出这样的代码,这样我们就要改,否则就一定不会改。例如typeof(null)返回的是object,大家也会觉得比较奇怪,针对这点之前也讨论过是否要修改,但是最后还是没有改,保持了原样。所以说继续写ES5和ES3也是可以的,代码是可以跑起来。但是新的版本肯定是有它的好处,毕竟是那些优秀的人聚集在一起,克服各种困难研究出来的,肯定是有些值得学习的地方。我可以举两个例子大家看一下:

1.ES6(ES2015)加了 Module,Module 这特性为什么要加,能不能不加,当然 Module 可以不加也可以用,有各种各样的方案,比如 CommonJS 方式可以达到类似的效果。其实这种方式有些问题,因为它不是标准的,有些人会想我也搞一套更好的行不行。虽然现在 CommonJS用的很多,但是在 Browser 中是无法直接用 CommonJS 的,肯定是它的某种变形,比较常见的是 AMD。所以我们需要一个更加统一的格式,像 Module 如果没有一个统一的标准,就没有办法成立了,它是一个重要的代码复用单元,如果不统一,各用各的,就无法进行下去了。而且 ES6 增加的 Module 是一个静态的,可以进行静态分析和更好的性能优化,webpack、rollup 还可以对打包进行简化,这些都是 CommonJS 不能做的,Module 还有很多的好处,具体大家可以看我的 Blog 上的相关文章,我记得之前有翻译过一篇相关的文章。

现在有些社区中非常有名的人,对加入 Class 持保留态度,有各种意见很正常,但是我想说的是,Class现在有很多人在用,又没有标准方式,虽然都大家都是基于原型的,但是还是会有些细微的差别,有时候一点差别比很大的差别更糟糕,因为当有BUG的时候反而更不容易被发现,既然有很多人有这样的需求,还不如把它标准化。

2.我们再举一个还没有进入标准的例子,可能就是明年的 ES2018 的,是与 Module 相关的,叫 dynamic import,dynamic import 就是你可以在代码里直接写入 import,它类似于函数,你传入 Module 名字,它返回 promise,promise 的值是 Module 对象,你就可以使用 Module 导出的函数。为什么它会被加入到标准里面呢?因为它是非常有用的,前面我们讲过 ES6 加入 Module 是静态的,它在程序运行之前已经存在了,所以它没有办法实现按需加载这样的需求,所以这样的内容需要被加入到标准里面。

所以对于学不学习新东西,单纯的从完成某些需求上来说,可以不用,因为老的方法也可以做出来,但是它可能会存在一些缺陷或者问题,新的东西肯定有它的优势,比如可能会提供更好的编程体验,或者与其他东西相关提供更好的性能等等诸如此类的原因,当然可能还有一个更实际的原因,就是新的技术如果不学,可能会被淘汰。一些公司招人的时候,肯定会问一些新的东西会不会,如果说不会,这肯定是个问题,当然说学这个不仅仅是为了求职,肯定是考虑去完成工作,去实现一些东西,利用这些新特性把它做得更好。这个东西其实是两面的,为什么说求职市场为什么要求你会这个,是因为是互为因果的关系。之后可能会有人会反过来这样提,我能不能只学新的,只学 ES2016、ES6 及以后的,不学 ES5、ES3 的某些东西,我觉得这肯定是可以的,你已经用了 let,const,你就回去不会搞那些 var 以及 var 那些奇奇怪怪的地方,如果你已经用了新的东西,当然可以不用去管那些比如说 with,因为 with 在 script 模式下 Module 里根本不能用,所以说学了没太大意义。反过来说,ES3,ES5一些老的边缘性东西可以不用去看,不用去学,但是这是对于初级、中级程序员来讲,高级程序员的话,可能还是要被迫去学一下,因为可能你需要维护老的代码,可能一些老的底层机制你还是要去研究一下,比如说你虽然已经不用去写class了,但是class底下还是有原型的,所以原型的机制还是要学习一下的,但是一般在用的时候,你完全不用底层原型也是可以的,比如说用 typescript,只要你一直用新的东西,你就不会触碰到原型,反而在某一些特定的场合,你需要用到的时候再去学习一下,再去深挖历史。

五、如何学习每年的新标准?

关于这个方面,我推荐大家去订阅一些博客或者一些比较好的网站,里面会有一些专栏,经常性会有一些有关于新特性的文章。对于如何学习新标准,这里推荐两种方法,一种是等待新标准发布,然后通过相关文章来了解,如果对具体的新特性比较关注,想实时了解, 也可以访问:https://github.com/tc39/proposals。tc39 就是 ECMAScript 制定标准的组织,这个仓库内部有比较完整的 ECMAScript 标准的文章,大家可以去查看。这个仓库的 Proposal 里面列了已经进入 tc39 流程的提案。 大家也可以去查看。所以当我们去查看仓库时,打开网页的readme,里面列举了许多active proposal,也就是它的stage是1到3,也就是在积极讨论中的提案,它上面还有一些链接,可以链接到 stage0 的 proposal 和 finish proposal,像 finish proposals里面是列举了已经讨论完成的 proposal,也就是要么已经进入今年新标准的要么是已经讨论完成,但是没赶得及进入今年新标准的,会进入下一年新标准的提案。比如我们打开 finish proposal,我们就可以看到 ES2016,ES2017 里面加的新的特性,其实都比较简单,在 ES2016 里面主要加了两个特性,一个是在数组上加了 includes 方法,比如原来怎么判断一个对象是否在数组里,是用 indexof 判断是否等于-1,写起来比较麻烦,现在用 includes 方法直接用来解决这个问题。那为什么这个方法不叫 contains 呢?其实这是个兼容性问题,在其他语言中都叫做contains,只是因为和 mootools 有关,因为代码里的 bug,如果叫 contains,则就不工作了,所以改名叫 includes。还有就是乘方的运算符,两个乘号连在一起就表示乘方,这个其实也比较简单,ES2016主要就是加了这两个特性。ES2017也就是今年发布的这个版本加的东西就比较多,比如像 values、entrance 这些新的 API,values、entrance 也比较容易理解,如果你已经用了ES5,比如像 object.keys 这个方法,其实你大概就知道values、entrance是干什么的了,然后还有像padding,其实是加了 padStart 和 padEnd 方法,也就是在字符串前面或者后面补一串特殊字符。还有就是函数参数,在调用的时候可以多加一个逗号,这个很简单,看一眼就能明白,这和数组或者对象每一个条目的最后面可以有一个多余的逗号,这主要是为了写代码方便,防止出错。

回过头我们再看一下还在讨论中的提案,其实很多浏览器都已经加上实现了,比如在proposal仓库首页的readme的第三个,Rest/Spread Properties,这是个对象,对象的构造可以直接用三个点去表示,这和数组有点像,这大家有兴趣可以自己去看一下。这里的proposal都可以点进去,里面的reason都有example实例代码,如果你不是深究到特性的一些边边角角,看example的实例代码就差不多可以了。这里面当然也有我前面提到的dynamic import以及符号的一些写法,可以用于动态的导入和按需加载的一些特性。大家看一眼可以知道,里面stage3草案里面有很多都跟正则表达式相关,这些很有可能会进入明年的标准里面,因为已经进入到stage3之中了,那有没有必要学呢,如果你现在的工作没有怎么用到,那就没必要,如果你的工作很多地方都用到正则表达式,那就去看一下。

六、如何在实践中采用新特性?

这里就要说到Babel了,它是一个转译器,它可以把新特性通过编译和转译,使其可以在没有新特性的老的浏览器上跑起来,但并不是所有的新特性都可以转译,不过大多数都是可以的。因为是Live,所以不能非常详细的介绍babel的配置,可以简单说一下,大家都知道Babel有preset,因为有preset,所以实际上用起来就比较简单。比如说你用了ES2016的preset,那么它可以把ES2016通过编译解决的一些特性可以编译成在ES2015上跑,以此类推,比如说你用了ES2017的preset,那么它可以编译成在ES2016上跑,如果你两个都用,那么可以ES2016、ES2017编译成在ES2015上可以跑,如果你比较细致化,你可以一个一个去开启,因为preset是由若干个bubble plugin组成,而每个bubble plugin对应一个或多个特性,所以你也单独使用某个bubble plugin去做特性转化。紫云飞的Blog中有很多ES6的文章,大家可以去学习。看到有人问到ES中的箭头函数,我先简单回答一下,它并不是为了让语法简单些,而主要是为了解决This的问题。This是动态的,是在运行的时候,才能确定它的值,但是在Error Function中解决了这个问题。

七、Stage0-4是什么意思?

Stage0-4表示每一个草案都有一个阶段,标明草案的成熟度:

  • stage0表示的是一个想法,比如说可以弄这样一个特性,写出来代码是什么,提交给委员会,并且委员会也觉得这个想法可以进入下一步;
  • stage1 表示委员会已经开会讨论过,觉得这个方向或想法可以进行下去,并且会指派一个负责人来跟进;
  • stage2 表示委员会对负责人的设计的语法和语义开始进行讨论;
  • stage3就开始涉及到实现,等到四大主要的浏览器实现的差不多了,开始进入下一步;
  • 一般来说stage4的提案,就可以进入标准了,这个新特性(提案)在一些浏览器stable版本上就可以使用了。

Stage0 和 stage2 的特性也不是完全不能用,只是会存在一些风险,比如说语义或者语法会被修改,最糟糕的就是提案有可能会被撤销。语法修改问题不大,因为可以自己写一个 Babel 插件,进行语法转换;语义修改会比较麻烦,具体的只能 case by case 的去看;被撤销的提案也有,但是非常非常少,大家平常应该遇不到。在工作中,如果你认为某些特性可能有问题或者有缺陷,可以在 GitHub 或者 ESDiscuss 邮件列表上面进行讨论,当然在提出疑问的之前,最好确认一下自己是不是已经很好的理解了这个特性。至于我们怎么样参与到标准的制定,方法有很多,比如可以通过 ESDiscuss 邮件列表、proposals、业界大牛的 Blog 来发表自己的观点、提交新特性的小测试,翻译新特性等等方式来参与标准的制定,当然也可以尝试自己提一个提案,提供自己的想法。

八、Typescript和JavaScript以及Babel和Typescript的区别和联系

Typescript简单点来说就是JavaScript+静态类型,在设计上确保对JavaScript兼容,称为JavaScript超级,如果想要更深入的了解Typescript可以访问:https://www.zhihu.com/question/64563945。其实Babel和Typescript的关系是有一些互补的地方,Typescript所关注的是怎么把静态类型加入到JavaScript语言中去,babel关注的是转化的问题,就是怎么把代码从一种形式转化到另一种形式,那么它就可以用来做很多事情,比如说可以用来做编译,比如说可以写一些插件等,Typescript也可以做编译,但目前为止这不是Typescript的核心东西,两则在架构上也有区别,Babel是插件化的,Typescript则没有很好的插件化。

九、ES201X在面试时,如何考察?

首先面试官一般不会特意考察新特性,除非一些非常重要的特性可能会问到。当然如果新特性能够非常好的回答上来,肯定是加分项。大部分面试官主要还是看你对新技术有没有追求,有没有求知欲。当然也是分人的,如果一个人对业务这块比较强,能够创造足够的价值,对他的新特性要求就没有那么高,只要有计划的去获取新知识就可以。如果是要求比较有冲劲的岗位,对新特性的要求会高一些,当然任何情况下多了解一些新特性肯定是好的。对于新人来讲,知道一些新特性对面试肯定是有帮助的,面试的思路就是没有成就,就讲经历,没有经历就讲心得,学习心得在这个时候完全可以展示出来。

作为面试官一般不太会问纯粹知识性的问题,比如API的名字是什么,参数是什么,返回是什么,这样的问题最多知道他有没有学过。面试官想要知道的是他对新特性有没有全面的了解,比如说异步,主要考察对异步的理解,不需要指定特定的新特性,而是看他如何来完成这个需求的。如何区别众多面试者呢,首先可以看他的代码,如果他涉及的比较多,可以更加详细的细问一下。二来可以把题目中加入一些额外的东西,比如异步处理中的异常处理,一下就可以看出区分度,实践过很多的人,对错误处理的经验也会比较丰富。再往下就需要case by case继续深挖了。

对于面试者,如果面试官问的你都知道那是最好的,如果不知道,你可以告诉面试官你知道一些什么,虽然有些具体的不是很清楚,很确定,但是你可以告诉面试官你通过一些渠道了解过。如果想要更加详细的了解面试这块,可以再去找一些相关资源深入了解一下,100offer 以前的Live也会涉及到这块,大家可以多去看一下。

最后大家要知道面试官不是想要刁难你,而是想要找到你的闪光点,而你要做的就是如何让面试官发现你的闪光点。

Q&A

Q:请问怎么通过做前端工程赚到钱?

这个问题还真有点不太好回答,只能说前端工程师这个职业,总体还是不错的,养家糊口是肯定没有问题的,如果能进入大厂,赚的会比平均收入高多了;就算不能进入大厂,二线的互联网公司,养家也是可以的,或者做一些外包项目也是可以的。

将来想做前端工程师,大学需要学习什么专业?应该做什么准备?

不仅是前端,任何编程方面的职业,计算机基础都是必须的,还有就是做一些项目,参与一下开源,打好基础就可以了。

Q:Node是否已经支持module?

@std/esm不是Node官方对module支持的方案,是社区搞得,他可以用在更低版本的Node上面。还有同学发https://github.com/nodejs/node/pull/14369,说是不是Node已经确定走mjs了。虽然Node官方是这样说的,但还是有不少反对意见,最终是什么样子还要再看,我个人也不是特别喜欢.js不同后缀名的方案,具体的比较复杂,我们就不细聊了,而且从整理来讲,还是相对次要的问题,关键还是要等整个Module直接得到支持。

Q:在面试的时候,是如何判断前端工程师是否优秀?

如何判断是否优秀,涉及的方面很多,如果我面试的话,我肯定要求现场写代码的。通过写代码可以看出他写代码的习惯,如何排错,如何使用搜索引擎,如果用百度搜,肯定是要扣分的,因为我那里都是可以直接使用谷歌的。

Q : 刚才贺老说很多人写的promise比较糟糕,想问一下一个好的promise应该如何去写,或者说应该包含哪些标准?

首先应该考虑到错误处理,我之前也说过了,异常处理是可以显示差距的地方,要知道什么时候去处理。还有就是不要有太多的嵌套,promise本来就可以把一个call back打平,如果你还是一层promise套一层promise,肯定有问题。Promise和call back有一个很大的区别,很多人直接从promise转到call back不太习惯的一点,promise其实需要把它转变成对值的处理,而call back是一个过程型,做好一件事,调下一个call back做下一件事,这个很难用语言来表达清楚,大家可以领会这个意思。当然,现在来讲,我会建议大家使用Async/Await的方式来写,这样不是说promise就不重要,而是用Async/Await很多麻烦的地方会比较好写。

Q : 以后JS如果臃肿起来会出现各种各样的定制版、简化版吗,类似coffeescript?

Coffeescript 和 JavaScript 有比较大的差别,Coffeescript的设计目标是在不大改变JavaScript的语义的基础上对语法简化。其实Typescript和Coffeescript有一些共通之处,Typescript也是不大改变JavaScript的语义的,但是它比 Coffeescript 更进一步,可以称为超级JavaScript,也就是所有的JavaScript特性在Typescript上都可以使用,但是Coffeescript并不是这样。例如coffeescript2(还没有发布正式版本)加了很多ES6的特性,但是没有包含所有的 ES6 的特性。

Coffeescript 虽然在语法上做了简化,但是也不能说完全只有简化,因为 Coffeescript1 刚出来的时候 JavaScript 还没有 Class,而 Coffeescript1 却加了 class。但是如果你想使用 class,使用 CoffeeScript 的 class 比其他方式会简单。

有些人可能认为从 ES6 开始 JavaScript 已经开始臃肿起来了,但是这个问题要看跟谁比,在语言的发展历史上,有很多非常复杂的语言,比如 C++。当这个语言还很小的时候,一个人就可以很容易的把它所有的特性都掌握了,如果你要加一个新特性的时候,就会衡量,但是当语言达到一个域值,再加一两条新特性也不是很明显,因为它本身就已经很大了。有人说 JavaScript 到 ES6 是不是已经跨过那个域值了,如果从横向比较的话,我觉得还没有。所以说对于定制版和简化版,如果就 C++ 语言来讲,我们现在使用的是它的一个子集,因为它支持很多的范式,而 JavaScript ES6 基本所有的特性都会用到,范式也相对简单,所以离定制版和简化版还差的比较远。至于以后会不会,不太好讲。

0a361d86be5f45798efb31ca8b2624d41481706060 80x80
王川川
100offer 行业观察者。每天,我都会透过 100offer 上人才流动数据了解互联网人才趋势,通过研究最热门的领域、最优秀的人才,建立对行业的深度理解。
标签:
评论
0条评论