面对前端六年历史代码,如何接入并应用ES6解放开发效率

栏目: JavaScript · 发布时间: 8年前

内容简介:面对前端六年历史代码,如何接入并应用ES6解放开发效率

写在最前

很荣幸有机会和大家分享自己在前端工作中的一些经验。更高兴能邀请我的同事颜海镜同我一起做这件事情。其实经验说不上,只是希望能更多的和大家一起交流、学习。

为什么要讲“面对前端六年历史代码,如何接入并应用ES6解放开发效率”这个主题呢?其实相信很多人认为ES6已经不再新鲜。在前端迭代迅速的今天,会不会有些“老生常谈”?我理解并不是这样的,因为 很多人其实对ES6的理解主要集中在新特性、语言用法等层面上。 这些内容是大部分学习者都能通过共享得到的。但是,对于ES6往往缺少了在实际大型工程中的接入和应用。尤其维护开发PV亿级以上的产品,并不是每个人都有机会的。

所以,相比于ES6语言本身, 我更希望能介绍一些工程上、设计上的想法,以及接入ES6过程中不为人知,但又至关重要的的“细枝末节”上。 同时,希望想了解BAT公司技术项目流程从立项到落地的读者、参与者能有所收获。

全篇文章分为五个部分:

  • 对前端发展的态度和看法。

  • 大型互联网公司对新技术的前期调研和评估。

    • 我们面临的历史背景。

    • 当我们说调研时到底在说什么。

    • 为什么非要折腾ES6。

  • 正确解锁ES6开发姿势。

    • 使用Babel进行ES6编译。

    • 传说中的“最佳实践”。

  • 一个设计实例。

  • ES6带来的困扰和展望。

篇幅并不短,其中还有一些ES6“黑魔法”和Babel编译分析,以及兼容性处理等内容。

第一部分:对前端发展的态度和看法

借用查尔斯·狄更斯在《双城记》中的不朽开篇来形容如今的前端开发,我觉得再合适不过了:

这是最好的时代,这是最坏的时代,这是智慧的时代,这是愚蠢的时代;这是信仰的时期,这是怀疑的时期;这是光明的季节,这是黑暗的季节;这是希望之春,这是失望之冬;人们面前有着各样事物,人们面前一无所有;人们正在直登天堂;人们正在直下地狱。

没错,我们脱离了之前“刀耕火种”的“脚本玩具”时期。伴随着nodeJS的强势崛起,社区交流的如火如荼,模块化开发的如虎添翼,HTML5的攻城掠地,彻底迎来了 前端“工业革命”的爆发。

同时,这也意味着大量的技术更迭。即便没有“南朝四百八十寺,多少楼台烟雨中”那般夸张,也足以让各阶段前端开发者疲于奔命,应接不暇。举个例子,想想我们也许刚熟悉了CommonJS,又要去了解AMD、CMD,稍不留神,就在2017年5月这个初夏:ES6 module要开始在浏览器端实现了!

好吧,也正好以此“ES6发展的标志性事件”来为这次分享拉开序幕,我们今天就要谈谈:ES6在大型项目中的接入和发展的方方面面。所谓“沉舟侧畔千帆过,病树前头万木春”,古诗中以“沉舟”、“病树”比喻纷扰和困惑,但却并不尤怨,反而表现的是一种对世事变迁和潮起潮落的豁达开朗。同样我们认为 ES6代表了未来,对未来理应拥抱。

全文看下来,也许你会理解“所有的发展都是站在历史的基础上”,停止不前的“沉舟”也有指引千帆航向的意义。“合抱之木,生于毫末;九层之台,起于垒土”。 技术更迭中,深厚的基础是多么重要。

这次分享,我们不会去把时间浪费在ES6新特性的讲解和语法细节层面上,这些内容毕竟都可以轻松且“免费”地找到。比如阮一峰老师的书中讲解就很透彻了。 我们会把重点放在ES6工程接入和开发维护上 ,背靠大流量的产品,这些不是所有人都能接触到的。

第二部分:新技术的前期调研和评估

我们面临的历史背景

先从背景说起,我们负责的项目是百度知识搜索部某明星产品,该产品代码历史在6年以上。在很多大型互联网公司里,这种“历史负担”其实屡见不鲜。也就不奇怪为什么知乎上会有人质疑:“QQ空间的前端技术水平如何?”,“为什么很牛的互联网公司代码却不能看?”等等。

在我们这边,历史问题主要集中在以下几点:

  • 使用古老Tangram类库,开发体验不友好。

  • 构建 工具 以FIS为主,但是版本不统一。

  • 模块设计不合理,内外耦合严重。

  • JS,需要兼容IE6+。

这些问题都会对ES6接入,造成一些潜在障碍。这就需要对新技术进行更加合理的评估和调研。

当我们说调研时到底在说什么?

也许会有一些读者认为“这有什么好调研评估的,不就是新的特性学习吗?”,其实在大型工程中这样的想法是片面的。

首先,对于新特性的熟悉,当然是最基本的。

此外,对于保证PV过亿的大型线上产品,就要求对ES6的方方面面面要足够了解。会一些let,const,箭头函数,模块化等语言层面知识还是不够的。

这就说明,在新技术前期调研工作当中,新特性、新语法的学习仅仅是很小的一方面。 同样重要的是执行环境保障、生产配置、线下开发流程、线上bug跟踪等各环节内容。

比如,这个项目的前期调研就包括但不限于:

  • 如何兼容旧版本浏览器(IE6+)?

  • 编译器/转换器是否真能摆平一切,应用是否完全可靠?

  • 编译器/转换器面临版本更新怎么办?

  • 编译器/转换器的接入对于现有的代码是否有影响?

  • 编译器/转换器的编译结果对于现有的代码是否有影响,能否完全兼容?

  • 引入ES6后开发效率是否真的可以提升?

  • 就算开发效率确实提升了,上线的代码量是不是更大了?对于产品性能是否有影响?

  • 所有可能产生的负面影响如何回滚?谁来担责?

  • ES6现在处于什么阶段,是否会被废除,就像第四版本一样?

  • 对于ECMAScript语言标准的提案分为哪几个阶段?

等等一切可能影响产品稳定或存在潜在Bug的问题......

为什么非要折腾ES6?

这个问题其实就是“如何评估ES6?”,“ES6的接入能带来哪些收益”。或者更直白一些:“你靠什么来说服技术经理,分配给你时间、人力去搞ES6?”毕竟大公司里的资源申(争)请(夺),都要拿收益来说话。

这就需要以自己所负责的业务为背景,在充分调研的基础上做出合理评估。

最终我们认为从以下几个角度来看,ES6的推广势在必行:

  • 解放开发效率。

    • 新特性的合理使用,优雅而简洁。

    • 减少第三方库的依赖。

    • 可维护性提升,代码量减少。

  • 面向未来。

    • 向标准靠拢。

    • 官方支持。

    • “迟早要学”。

  • 其他方面。

    • 提升技术先进性。

    • 促进技术交流,提高技术氛围。

    • “编程激情”。

    • 整合部分历史代码的好机会。

    • 面试中的加分项。

以上是出于我们自身产品开发的角度。同时,整个前端在ES6发展环境和普及率上,我们参考了ponyfoo.com在2015年底做的一个知名调查: JavaScript Developer Survey Results ,该调查以5千多个前端开发者为背景,得出以下结论:

  • ES6普及率?

面对前端六年历史代码,如何接入并应用ES6解放开发效率

  • ES6是否是一个很重大的版本进步?

面对前端六年历史代码,如何接入并应用ES6解放开发效率

  • 你都使用哪些ES6新特性?

面对前端六年历史代码,如何接入并应用ES6解放开发效率

所以,不管是因为 大势所趋 还是从 自身收益 出发,我们决定了ES6接入作为该年度最大的技术项目之一。

第三部分:正确解锁ES6开发姿势

使用Babel进行ES6编译

目前各大浏览器和开发环境对ES6的支持情况参差不齐,我们的产品对浏览器兼容性要求又比较高。所以,当然不能荒谬地“裸写”ES6代码,发布上线。因此,在实际项目开发中,需要降级为ES5语法以兼容各平台。

幸好有几款工具可以将ES6语法转换成ES5,让我们在使用ES6新特性编写代码的同时,不需要考虑具体的兼容性情况。比较知名的两款编译器为:

  • Babel

  • Traceur

我们选择了Babel 5.x版本,主要是因为以下几个原因:

  • Babel对ES6的支持程度比其它同类更高或相当。

  • Babel拥有完善的文档和较好体验的在线编译环境。

  • Babel使用广泛,用户基础好。

关于第一点原因的主要数据支持可以在Bebel官网,我们可以看到不同版本Babel对ES6跟进和支持的情况;

另外,关于在线编译平台,可以访问官网: 进行体验 ,这对于研究Babel编译结果十分方便。

关于Babel的接入和使用方法,社区上的资料很多,这里不再进行科普浪费时间了。以下,从几个关键性的工程问题进行延伸。

配合构建工具

首先,因为我们使用的是百度自己的FIS来做前端构建工具,所以只需要在FIS的配置文件中加入依赖,并安装插件就可直接使用。这一切,就像社区上使用更多的webpack一样。

babel-polyfill

同样需要说明的是, Babel默认只转换新的JavaScript语法(syntax),而不转换新的API。

比如:Babel可以编译let, const等特性,但是诸如Iterator、Generator、Reflect、Promise等全局对象,或者数组实例的find这些新的方法并不会得到编译。如果想让这个方法运行,必须使用babel-polyfill, 同时要保证这个polyfill在你的所有其他脚本之前就要加载执行。同时,因为编译产出为ES5代码,所以又要处在ES5垫片ES5-shim,ES5-sham之后。

实际情况中,我们放弃了使用babel-polyfill,这是出于减少JS引用的考虑。我们页面已经加载很多JS了,并且babel-polyfill由于其特殊性(抢先执行),难以和其他业务脚本打包。再者,我们认为ES6新增的这些方法的必要性并不绝对。就像上图统计的那样,ES6新特性被广泛使用的大多是let, const, 解构,箭头函数等,这些使用默认Babel编译就已经可以达到要求了。

当然,Promise这个使用广泛的特性我们专门引入了单独的polyfill来处理。这样的定制化完全可以满足需求。

babel-runtime

babel-runtime是为了减少重复代码而生的。Babel编译生成的代码,可能会用到一些_extend(),classCallCheck()之类的工具函数(后文在分析编译结果部分会有介绍)。默认情况下,这些工具函数的代码会被引入在编译后的文件中。如果存在多个文件,那每个文件都有可能含有一份重复工具函数的代码。

这种冗余一定是我们不能忍的。

babel-runtime插件能够将这些工具函数的代码转换成require语句,指向为对babel-runtime的引用,如 :

require('babel-runtime/helpers/classCallCheck');

这样,classCallCheck这个工具函数的代码就不需要在每个文件中都存在了。当然,最终你需要利用webpack之类的打包工具,将runtime代码打包到目标文件中。

但是要注意,这是Babel 6版本才引入的,对我们来说,这就面临一个关于“Babel版本升级部署”的问题。

关于这个插件的更多介绍,同样可以在 官方网站中找到。

Babel的部署和升级

在真正部署Babel的前前后后,我和我的同事针对每一个ES6特性的编译稳定性都进行了严密的测试。测试包括了验证黑盒输出情况和不同浏览器的支持情况,以确保上线后的万无一失。

另一方面,我们在使用的Babel版本就如上所说,为5.x,当然Babel在社区的蓬勃发展和自身定位的调整,使得自身版本更新换代也非常频繁。同时,随着越来越多的库升级至babel6,将我们的项目升级至babel6似乎也有必要。这样的升级工作想想也确实头疼,尤其是要保证线上代码的稳定运行。

截止目前为止,我们还未对Babel进行升级,因为这个需求还并不迫在眉睫。但是,着眼于未来还是很有必要的。我们及时关注了Babel 6.x版本带来的新变化。这方面对于大家的建议其实只有一个,就是紧盯官网+快速调研。 点击这里 会把大家链接到Babel官方博客,里面同步了每一次更新的细枝末节,内容非常详尽。

同时,你可能会问,那我们就保持初始版本不去升级,岂不是一劳永逸了吗?

当然不是这样,我认为,每一个版本的迭代和演进自然有其原因。如果一直固守成规,不管是在代码组织上和工程化上都会吃亏。除了刚才提到的babel-runtime插件,新版本的Babel(5.x-6.x)收益还体现在:

  • 性能提升:据说compile速度提升20%。

  • 可配置的插件:更强的灵活性,以及更简单的插件API.

  • 更简洁的配置。

选择编译和其他

在进行ES6编译的同时,对于大量的历史代码文件,我们不会进行ES6的翻新重写。这些历史代码因此就不需要使用Babel进行编译。为此,我们使用了文件后缀名来进行区分,并在构建工具的配置文件中进行正则匹配,达到选择性编译的效果。最终的规范是,ES6代码统一以.es为后缀名。

最后,Babel社区的蓬勃发展,导致“你以为的Babel”其实已经不再是那个Babel了;同时,Babel知识的广泛性远远超乎了很多人的想象,比如Babel编译的loose模式、normal模式;比如Babel依赖的引擎babylon;比如babylon fork的acorn;比如Babel将源码转换AST的理解等等。很多东西其实我研究的还只是皮毛,但是不到浏览器广泛支持ES6的一天,不到摆脱兼容性需求的一天,恐怕我们是脱离不开Babel了。

传说中的“最佳实践”

在ES6大量的新特性中,我们推荐并有广泛应用的包括但不限于:

  • 默认参数

  • 模版表达式

  • 多行字符串

  • 解构赋值

  • 改进的对象表达式

  • 箭头函数 =>

  • Promise

  • 块级作用域的let和const

  • 模块化

当然还有很多优秀的新特性,但是在应用中频率相对较少,不再一一列出。

我认为,一切所谓的最佳实践都要依赖基础。在抛出几个“奇技异巧“之前,我想从一个简单的例子说起。

const例子:

举一个简单的例子(出自阮一峰ES6一书),可能大家都了解const声明一个只读的常量。一旦声明,常量的值就不能改变。

const a = 4;
    a; // 4
    a = 3; 
    // TypeError: Assignment to constant variable.

为此,我们可以延伸出:const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

const b;
    // SyntaxError: Missing initializer in const declaration

同时,我们还要注意:const的作用域与let命令相同: 只在声明所在的块级作用域内有效。

因而,它也 不存在常量提升的概念。

但是,还需要了解的是:

const实际上保证的,并不是变量的值不得改动, 而是变量指向的那个内存地址不得改动。

对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。

const foo = {};

    // 为 foo 添加一个属性,可以成功
    foo.prop = 123;
    foo.prop // 123

    // 将 foo 指向另一个对象,就会报错
    foo = {}; // TypeError: "foo" is read-only

上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。 不可变的只是这个地址 ,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

所以,仅仅就是一个声明常量的const,里边牵扯出的基础内容却很多。这就需要在掌握ES6基本用法的同时,需要有更强大的基础概念才能进一步提升理解。

这里,给大家留一个思考题目: 如何真的讲一个对象冻结?

ES6黑魔法:

其实我想大家对ES6特性越来越熟悉,以及社区的大力宣传,一些ES6黑魔法已经“非常平常”了。

比如,扩展运算符结合解构赋值,除了“你想象的那种用法”外,它还可以优雅完成:

  • 合并数组

    arr1.push(...arr2); // 把arr2合并到arr1之后
      arr1.unshift(...arr2); // 把arr2合并到arr1之前
      let arr2 = [1, 2, ...arr1, 4]; // 数组内合并数组
  • 复制数组

    let arr2 = [...arr1]; // 相当于arr1.slice()
  • 把伪数组转为数组

    [...document.querySelectorAll('div')]
  • 交换两个变量值

    [a, b] = [b, a]; // 不再需要中间变量

等等。。。

具体可见 这里。 或者英文好的可以 戳这里: Six nifty ES6 tricks

Babel到底编译成了什么?

这是一个很关键的问题。也是正确使用ES6的高难度姿势。

因为我们所有的ES6代码都依赖Babel编译,所以如果你不去了解它的编译产出,那么最后上线的代码都是“心里没底”的。

举例来说,我刚才提到的const,在经过Babel编译后其实一律换成var;

可能你紧接着会问:“那如何保证不变性呢?”,原因就在于如果你在源码中第二次修改const常量的值,babel编译会直接报错。

这是一个比较轻量甚至取巧的例子。接下来, 我们再来看看class+extends的编译情况。

Javascript实现OOP其实一直以来都是热门话题,这些争议性的内容我们不去讨论。先来看看Babel的实现过程。

class Person {
        constructor(){
            this.type = 'person'
        }
    }

会被编译为:

var Person = function Person() {
        _classCallCheck(this, Person);
        this.type = 'person';
    };

我们看到,还是用了构造函数来完成。同时,上文提到过的_classCallCheck也出现了,他作为工具函数,保障class调用的正确性:

function _classCallCheck(instance, Constructor) { 
        if (!(instance instanceof Constructor)) { 
            throw new TypeError("Cannot call a class as a function"); 
        } 
    }

关于继承:

class Student extends Person {
        constructor(){
            super()
        }
    }

编译结果:

// 实现定义Student构造函数,它是一个自执行函数,接受父类构造函数为参数
    var Student = (function(_Person) {
        // 实现对父类原型链属性的继承
        _inherits(Student, _Person);

        // 将会返回这个函数作为完整的Student构造函数
        function Student() {
            // 使用检测
            _classCallCheck(this, Student);  
            // _get的返回值可以先理解为父类构造函数       
            _get(Object.getPrototypeOf(Student.prototype), 'constructor', this).call(this);
        }

        return Student;
    })(Person);

上面_inherits方法的本质其实就是让Student子类继承Person父类原型链上的方法。它实现原理可以归结为一句话:

Student.prototype =  Object.create(Person.prototype);
Object.setPrototypeOf(Student, Person)

所以说到底,还是“构造函数+原型原型链”内容,并且辅助Object.create等ES5功能实现。

我建议大家对于编译源码尝试去进行了解,对于自己的基础也是一种提高。

了解了这些,对于ES6的接入是很有帮助的。试想一下,我们在ES6环境下声明的类,如何在历史代码中(ES5环境下)实现继承呢?

通过对Babel编译结果的研究,我也实现了一个工具函数,用来完成这两种开发环境下类的衔接和过渡。具体代码实现难度不大,可以简要参考:

function inherits(childClass, superClass) {
        childClass.prototype = Object.create(superClass.prototype, {
            constructor: {
                value: subClass,
                enumerable: false,
                writable: true,
                configurable: true
            }
        });
        // 这里注意兼容性,IE11以上才完全支持
        if (Object.setPrototypeOf) {
            Object.setPrototypeOf(childClass, superClass)
        }
        else {
            childClass.__proto__ = superClass;
        }
    }

如果您有兴趣,可以看我的系列文章: 揭秘babel的魔法之class魔法处理。

打通两种开发环境的任督二脉

这里还是聊聊上面展示inherits工具方法,其实这属于“打通ES5和ES6环境”。同样还是在ES6环境下定义的Person Class,ES6环境代码:

class Person {
        constructor(){
            this.type = 'person'
        }
    }

在ES5环境中就可以直接进行引用并继承Person类,ES5环境代码:

funtion Student () {
        ...
    }

    inherits(Student, Person);

这当然是极其有必要的。想象一下6年代码历史,ES5环境的代码量是多么的庞大,这样我们在维护过程中,便可直接获利于ES6的特性。

同样,对于模块化上,我们也存在两种环境共生的问题:之前的代码我们遵循了commonjs规范,并通过打包工具(FIS部分功能),来保证浏览器端的支持。接入ES6之后,自然也就有了ES6模块化的写法。

那么JS文件内如何兼容这两种模块化写法的表达方式呢?

也很简单,同样依赖于Babel的实现。我们在Babel官网上可以找到关于模块化插件的内容:

面对前端六年历史代码,如何接入并应用ES6解放开发效率

其中有一个es2015_modules_commonjs,就是将ES6 Modules编译转换成commonjs形式的。我们当然选用这种编译方式。

对ES next支持

截止目前,ES7也已经取得了重大进展。很多最新一代的ES特性已经被广大开发者熟知并应用。那么在我们的环境中,对于ES next的支持也自然要跟进。这又回到了Babel的话题,我们当然还是离不开这个神器。

同时,你首先要知道,ES7不同阶段语法提案包括:

  • Stage 0:Strawman: just an idea, possible Babel plugin.

  • Stage 1:Proposal: this is worth working on.

  • Stage 2:Draft: initial spec.

  • Stage 3:Candidate: complete spec and initial browser implementations.

  • Stage 4:Finished: will be added to the next yearly release.

对应的,官方提供以下的规则集来对不同阶段的特性进行编译,你可以根据需要安装:

  • $ npm install --save-dev babel-preset-stage-0

  • $ npm install --save-dev babel-preset-stage-1

  • $ npm install --save-dev babel-preset-stage-2

  • $ npm install --save-dev babel-preset-stage-3

需要注意的是,这些工作应当在初期调研设计时,就要有规划和方案。而不是,今天头脑一热,想应用async/await ES7新特性,再去花费时间进行了解。因为,在公司内成熟的开发体系中,严谨的排期需求与个人私下的学习了解完全是两码事。

这些年踩过的兼容性的坑

我们代码能够兼容到IE6+,接入ES6之后,对于兼容性的保证是个挑战。在实际情况中,我们也踩过这方面的坑。

Babel对于ES6的编译是在ES5之上的,那么想要兼容IE6,自然编译产出的ES5代码是无法满足要求的。为此,解决方式只有提供ES5的polyfill,并保证在所有其他脚步加载之前执行。

我们采用了最出名的ES5-shim+ES5-sham来进行ES5代码的“降级”。期间各种IE版本兼容性的测试,那可谓是“一把鼻涕一把泪”。

同时,这里所指的兼容性也不仅仅是浏览器兼容性。也要考虑到引用社区上第三方组件库、类库的问题,如果这些源代码是基于ES6的,那就要慎重考虑是否符合我们使用的Babel版本,我们是否保证并兼容了Babel插件进行编译等相关性问题。这当然也是不小的工作量。

第四部分:一个设计实例

这个实例充分反映了ES6 class带来的便捷之处。

我们产品当中,一个页面可能存在多处“收藏”组件:点击按钮,对页面进行收藏,成功收藏之后,按钮的状态会变为“已收藏”,再点击不会有响应。

面对前端六年历史代码,如何接入并应用ES6解放开发效率

面对前端六年历史代码,如何接入并应用ES6解放开发效率

这样就出现页面中多处“收藏”组件之间通信问题,点击页面顶部收藏按钮成功收藏之后,页面底部的收藏按钮状态也需要变化,进行同步。

其实实现这个功能很简单,但是历史代码实现方式较为落后,耦合严重。良好的设计和肆意而为的实现差别是巨大的。

在利用ES6设计之后,我们的所有组件(包括收藏组件)都会继承UIBase:

class Widget extends UIBase {
        constructor() {
            super();
            ...
        }
    }

而UIBase本身会产生一个全局唯一的UUID,这样使得所有组件都有一个唯一的ID标识。同时,UIBase又继承“EventEmitter”这个pub/sub模式组件:

class UIBase extends EventEmitter{
        constructor() {
            super();
            this.guid = guid();
        }
    }

因此,所有的组件也同样拥有了pub/sub模式,既事件发布订阅功能。这就相对完美的解决了组件之间的通信问题。达到了“高内聚、低耦合”的效果。

具体来说,我们的任何组件,当然包括收藏按钮在发起收藏行为时:

widget.fire('favorAction');

同时,其他的收藏组件:

widget.on('favorAction', function(){
        ... // toggle status
    })

具体的实现结构如图:

面对前端六年历史代码,如何接入并应用ES6解放开发效率

这样的组件行为在一些先进的MVVM、MVC等框架中可以良好的实现。比如优秀的react框架中,我们可以对组件的state设计并切换。但是,我们的技术栈还停留在传统的操作DOM中,jquery类似类库可以满足我们的业务需求。我认为,所有抛离业务场景和需求的的谈新框架,也是一种“耍流氓”。

第五部分:那些年ES6带来的困扰和展望

不可否认,ES6的接入并不是百利而无一害的,我们要正确客观地看待它。伴随着开发效率提升的同时,它还带来了以下困扰:

  • 额外的编译流程。

  • 编译代码排错追错成本。

  • Babel版本升级是个负担。

  • api转换还需shim.

  • 潜在的bug.

  • 很多特性面向node.js,浏览器端并不实用。

  • 学习成本。

然而,未来已来,接下来我们又该做什么呢?

  • 更大范围的重构。

  • 紧盯ES6实现和ES next发展。

同时,需要指出的是ES6的先进性,还体现在和React框架的配合上。去年,我们团队也接入了React开发栈,ES6+React让我们更加面向未来。

最后,呼应一下本文开篇,谈一下想法和总结。每一名前端开发者可能都会感觉到处在前端发展的历史时刻。面对未来,我们也许正在感受着葡萄牙诗人安德拉德的诗句:

我同样不知道什么是海,

赤脚站在沙滩上,

急切地等待着黎明的到来。

ES6注定载入开发史册,最后也许也难逃被替代的命运,完成承前启后的使命。同样是葡萄牙人的诗句:

大陆,在这里是尽头;大海,在这里才开头(陆止于此,海始于斯)。

在技术的海洋里,这一站,既是一种结束,更是一个开始。

实录:《Lucas:ES6解放开发效率接入应用实战解析》

面对前端六年历史代码,如何接入并应用ES6解放开发效率

面对前端六年历史代码,如何接入并应用ES6解放开发效率


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Shallows

The Shallows

Nicholas Carr / W. W. Norton & Company / 2010-6-15 / USD 26.95

"Is Google making us stupid?" When Nicholas Carr posed that question, in a celebrated Atlantic Monthly cover story, he tapped into a well of anxiety about how the Internet is changing us. He also crys......一起来看看 《The Shallows》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具