深入探究ES6之模組系統

Super Mouse發表於2019-02-28

在上一篇《前端模組化,AMD和CMD的區別總結》中,介紹了commonJS規範下衍生出來的AMD和CMD。多年來,前端的js程式碼大都是以這種方式組織起來(再早連這個都沒有。。。),但是從語言設計本身的層面上講,官方一直沒有設計出javascript的模組系統,直到。。。ES6的正式釋出!

可以說ES6的正式釋出(討論了十年)是前端界翹首以盼眾望所歸的事,它是javascript被建立以來最重要的更新之一。而其中最重要的就是JS模組化的定義,從原生語法上支援了匯入與匯出模組,我們終於不再需要使用一些庫(Requirejs、Seajs等)來模仿模組化了。

本文不想過多介紹如何使用ES6模組的語法(比如import和export的規範),因為網路上關於這方面的介紹已經很多了,現在來說點不太常被提及但是對理解有很重要的東西。

“模組”是自動執行在嚴格模式下並且沒有辦法退出執行的JavaScript程式碼。模組有三個比較顯著的特性:

1、在模組頂部建立的變數不會自動被新增到全域性作用域(比如windows下),訪問模組的變數必須通過匯出的方式。

2、在模組頂部this的值是undefined。

3、模組不支援HTML的程式碼註釋。

以上也是ES6模組區別於傳統模組系統很重要的三點,而且ES6模組系統與傳統模組系統更顯著的一個區別是:

4、ES6的模組系統是靜態解析的

舉例:

if(Math.random()){
    import name from `./example.js`   // 丟擲錯誤
}
-------------------------------------------------
let name = `js`
if(Math.random()){
    export {name}   // 丟擲錯誤
}
複製程式碼

import和export不能在條件語句或任何動態方式中使用,原因是要讓JavaScript引擎靜態地確定哪些模組可以匯出。
如果使用過RequireJS或者SeaJS的開發者應該深有體會,它們可沒有這樣的限制。
由於ES6模組的靜態性,導致了一個怪異甚至讓人困惑之處,先看一個例子:

//a.js
let name = `ajs`;
let setName = fuction(newName) {
    name = newName;
}
export {name, setName}

//b.js
import {name, setName} from `./a.js`;
console.log(name)   // `ajs`
name = `bjs`    // 丟擲錯誤
setName(`cjs`)
console.log(name)   // `cjs`
複製程式碼

b.js只是簡單的引用了a.js中的值,而不能改變a.js中的值,當呼叫setName(`cjs`)時會回到a.js中去執行,並將其中的name設定為`cjs`。這說明ES6模組輸出的是值的引用,與CommonJS(輸出的是值的拷貝)完全不同。

至於將ES6模組系統設計成靜態的原因,大家可以參考這篇文章Static module resolution。其中原理較為深奧,個人認為可以不求甚解。

PS:動態import(不是ES6的內容)

凡事有利就有弊,靜態性的模組系統在帶來一系列好處的同時,也限制了開發者對於專案靈活性的掌控。比如在某些條件語句或是使用者點選觸發的操作裡面,動態(或者說按需)匯入模組的要求就變得很迫切。不過還好,現在動態匯入的提案已經存在於TC39第三階段了。

你可以這樣使用:

if(Math.random()){
    import(`./example.js`).then((M)=>{
        let Mod = M.default
        // TODO
    }) 
}
或者
if(Math.random()){
    import(`./example.js`).then(({setName})=>{
        setName(`Dynamic`)
        // TODO
    }) 
}
甚至是這樣
const locale = `en`;
import(`./utils_${locale}.js`).then(
  (utils)=>{
    console.log(`utils`, utils);
    utils.default();
  }
);
複製程式碼

·你可以在延遲載入、條件載入和使用者操作的情景下使用動態匯入
·動態import()可以在指令碼的任何地方使用
·import()能夠傳遞字串,你可以根據你的需求構造匹配符

歡迎大家積極留言指出問題及不足,我會及時修改文章內容,我們也可以一起探討一些技術問題,道理越講越清楚。

相關文章