麵對前端六年曆史代碼,如何接入並應用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開發姿勢
使用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);
thistype = '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官網上可以找到關於模塊化插件的內容:
其中有一個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設計之後,我們的所有組件(包括收藏組件)都會繼承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
})
具體的實現結構如圖:
這樣的組件行為在一些先進的MVVM、MVC等框架中可以良好的實現。比如優秀的react框架中,我們可以對組件的state設計並切換。但是,我們的技術棧還停留在傳統的操作DOM中,jquery類似類庫可以滿足我們的業務需求。我認為,所有拋離業務場景和需求的的談新框架,也是一種“耍流氓”。
第五部分:那些年ES6帶來的困擾和展望
不可否認,ES6的接入並不是百利而無一害的,我們要正確客觀地看待它。伴隨著開發效率提升的同時,它還帶來了以下困擾:
-
額外的編譯流程。
-
編譯代碼排錯追錯成本。
-
Babel版本升級是個負擔。
-
api轉換還需shim.
-
潛在的bug.
-
很多特性麵向node.js,瀏覽器端並不實用。
-
學習成本。
然而,未來已來,接下來我們又該做什麼呢?
-
更大範圍的重構。
-
緊盯ES6實現和ES next發展。
同時,需要指出的是ES6的先進性,還體現在和React框架的配合上。去年,我們團隊也接入了React開發棧,ES6+React讓我們更加麵向未來。
最後,唿應一下本文開篇,談一下想法和總結。每一名前端開發者可能都會感覺到處在前端發展的曆史時刻。麵對未來,我們也許正在感受著葡萄牙詩人安德拉德的詩句:
我同樣不知道什麼是海,
赤腳站在沙灘上,
急切地等待著黎明的到來。
ES6注定載入開發史冊,最後也許也難逃被替代的命運,完成承前啟後的使命。同樣是葡萄牙人的詩句:
大陸,在這裏是盡頭;大海,在這裏才開頭(陸止於此,海始於斯)。
在技術的海洋裏,這一站,既是一種結束,更是一個開始。
原文鏈接:https://mp.weixin.qq.com/s/zt-AOOiKjq96QaKFaTTUWg
最後更新:2017-06-20 11:01:52