ECMAScript 6 的模塊相比 CommonJS 的require (...)有什麼優點?
感覺語法比 CommonJS 繁瑣多了
http://es6.ruanyifeng.com/#docs/class
只要不是最壞的標準,那就一定比沒有標準強
ECMAScript 6 很多新功能都是毀譽參半,其中添加的一個新功能「模塊 Module」也一樣,有人認為 Module 可以幫助我們更好地寫代碼,也有人認為這增加了 Javascript 的複雜度,大多數人其實並不需要它。
到底是好是壞,這裡不去辯別。但目前 Module 的語法已經定下來了,我們可以來探索下它。
ECMAScript 6 的模塊有什麼優點?
三個字:爽,快,強。
爽?1. 語言層級支持,無需引入第三方庫2. 統一的 API,不用再寫 [shim](umdjs/umd · GitHub)3. 清爽的語法(與 Python 相似),功能卻很豐富:import:import * as _ from "src/lodash"; // 引入外部文件所有對象
import { each, map } from "src/lodash"; // 引入外部文件部分對象
import _ from "src/lodash"; // 引入外部文件默認導出對象
import _, { each, map } from "src/lodash"; // 同時引入默認導出對象和部分對象
import "src/lodash"; // 只載入外部文件,但啥都不引入
export let _ = function () {}; // 導出 _ 對象
export function lodash () {}; // 導出 lodash 函數
export default function (x) {return x}; // 導出匿名函數並設為默認導出對象
export { _, lodash as default }; // 一次導出多個對象
4. 由於可以選擇性引入並重命名外部模塊的部分對象,因此全局變數不被污染,局部變數也不怕被污染。
快?
1. 靜態代碼分析基於目前第三方依賴管理工具的實現,我們要通過運行時檢查當前模塊引入了哪些外部模塊,效率較低。但現在有了新語法的支持,我們就可以在運行前判斷得出模塊之間的依賴關係,進行代碼檢查。2. 上一條已經很勁爆了有木有 強?1. 更好地支持循環依賴 循環依賴示例:/* --- a.js --- */
import * as b from "js/b";
// 在模塊中間調用其它模塊的方法
b.bar("b");
export function foo (from) {
console.log("caller: " + from);
}
/* --- b.js --- */
import * as a from "js/a";
// 在模塊中間調用其它模塊的方法
a.foo("a");
export function bar (from) {
a.foo(from);
}
/* --- main.js --- */
import {bar} from "js/b";
bar("main");
結果:
caller: b a.js:7
caller: a a.js:7
caller: main a.js:7
2. 提供模塊載入器介面(Module Loader API)
有了這個介面後,模塊的載入就有了更多的可能性,比如動態載入,載入後回調等。但我對於這個介面熟知不多,詳見介紹: The ECMAScript 6 module loader API。延伸閱讀:- harmony:modules [ES Wiki]
- ECMAScript 6 modules: the final syntax
少了外部工具依賴,原生api效率較高,看了一些相關wiki,使用靈活度也比現在amd,cmd都方便,向下兼容度不高,不支持的如果要寫shim,不太方便,有人已經寫好了,但是原理都是ajax讀文本再做解析,效率通用性跨域能力都弱,所以,真正大規模推廣使用,還很久遠。
當然,通過上線前的預編譯和debug時的動態解析工具來做開發,還是挺爽的。
參見類似項目:ES6 Module TranspilerTreeShaking
雖然這是 Webpack 2 中的新特性,但是它與 ES6 模塊化有著千絲萬縷的關係。
下面這段代碼:
module.js
export const sayHello = name =&> `Hello ${name}!`;
export const sayBye = name =&> `Bye ${name}!`;
index.js
import { sayHello } from "./module";
sayHello("World");
假設這個工程一共只有兩個文件,那麼sayBye() 方法雖然沒有被使用過,但是仍然會被 export。然而如果我們在 Babel 中啟用 ES6 模塊化,同時升級到 Webpack 2.0/3.0 那麼就可以輕鬆實現 TreeShaking(利用的是 Webpack 2+ 的 Native Import 特性),最終的效果是只有 sayHello() 會被作為 module 的一部分導出。
只需要用下面的代碼就可以啟用 Babel 的 ES6 模塊化。
.babelrc
{
presets: [
[ "es2015", { modules: false } ],
...
],
plugins: [...]
}
請注意,modules 屬性的值只能是 false,不支持 true,在過去我們沒有設置 module 屬性時,Babel 會將 import 轉譯成 CommonJS 的 require(),再有 Webpack 去處理 require() 的邏輯。而將 module 變為 false 後,Babel 會直接輸出 import 語句,轉由 Webpack 去實現所謂 native import 的邏輯,同理 export 語句也是由 Webpack 去實現轉譯的。
1. 使用保留關鍵字 import 和 export ,從而在瀏覽器實現後能最大程度的向下兼容。
理論上現有網站的代碼可能使用了 require、exports、module 等變數,而且並非用於標準的 CommonJS 實現。
2. 使用聲明式語法,而非特殊的函數調用。
CommonJS 語法可能的兩個小瑕疵:var require = function() {}; // 覆蓋
var module = require("module"); // module is undefined
var delete = require; // 引用 require
var module = delete("module"); // 代碼含義容易混淆
ECMAScript 6的模塊處理方式有兩種,一種是通過import、export這種關鍵字實現的靜態方式;另一種是通過全局變數System實現的可動態編程的方式(相關標準還在制定中,目前的API還不穩定)。
對於靜態方式,使代碼的靜態分析更加輕鬆,方便做代碼檢測等。而動態方式主要用於瀏覽器端,方便瀏覽器非同步載入。
靜態方式的語法與其它語言很類似(比如python),從其它語言轉過來的開發者接受起來比較輕鬆。
我個人的話不贊同說ES6毀譽參半,或者說ES6毀大於譽。
很多傳統的前端人員可能剛開始一看到ES6的語法就傻眼了:這還是我認識的js嗎?可能還會想,變化這麼大,又要花時間學習了,又要重新積累一些東西了,這不是瞎折騰嗎?
我剛開始也有這些想法,但是後面逐漸深入接觸了ES6之後發現,確實值得這麼做,因為這讓js逐漸成熟起來,逐漸能承擔一些大型多人項目的開發。這些好處,真的是一時半會兒列舉不完。
規範規範規範,規則,有規矩才成方圓
CMD是國內玉伯大神在開發SeaJS的時候提出來的,屬於CommonJS的一種規範,此外還有AMD,其對於的框架是RequireJS1、二者都是非同步模塊定義(Asynchronuous Module Definition)的一個實現;2、CMD和AMD都是CommonJS的一種規範的實現定義,RequireJS和SeaJS是對應的實踐;3、CMD和AMD的區別:CMD相當於按需載入,定義一個模塊的時候不需要立即制定依賴模塊,在需要的時候require就可以了,比較方便;而AMD則相反,定義模塊的時候需要制定依賴模塊,並以形參的方式引入factory中。區別看下邊例子://AMD方式定義模塊
define(["dep1","dep2"],function(dep1,dep2){
//內部只能使用制定的模塊
return function(){};
});
//CMD
define(function(require,exports,module){
//此處如果需要某XX模塊,可以引入
var xx=require("XX");
});
4、JavaScript語言是弱結構性的,通過CommonJS定義一些規範,CMD和AMD得定義模塊的方式對代碼進行管理,使得更易維護;此外,NodeJS的誕生,對模塊的規範定義,和包(npm)的概念的引入,讓JS管理不再困難,一個字,爽爆了!
import, export, default, as, from 增加了5個關鍵詞,使用層面也比原來的複雜很多。
看個代碼,大家如果不去執行,僅憑理解看看是什麼結果。
下面這兩段有啥區別var log = console.log.bind(console);
export {log};
var log = console.log.bind(console);
export {log: log};
import config from "./config";
const config from "./config";
不再引用seajs和requirejs就能使用模塊就是最大的優點
# 語法級實現,便於做靜態分析。
類似 Browserify 這類工具想把 CommonJS 模塊打包放瀏覽器,因為 CommonJS 只是一個 function 調用,只能在運行時確定結果,想要確定哪些模塊是需要的、哪些不需要是辦不到的。(目前他們的實現要麼全部打包,要麼非常保守地只要寫了 `require()` 就當作需要該模塊)
eg.
```if ( Date.now() &> 150000000 ) require("foo")```# 標準化CommonJS 倒不說,各種 AMD、CMD 都可以再見了。推薦閱讀:
※a=new b()和a=b(),其本質的區別在哪?
※使用markdown製作的html幻燈片有哪些?
※node.js 已經淡出眾多開發者的視野了嗎?
TAG:JavaScript | Nodejs | CommonJS | ECMAScript2015 |