一些資料
阮一峰的《ECMAScript 6 入門》中,有對(duì)模塊機(jī)制的詳細(xì)介紹:
http://es6.ruanyifeng.com/#docs/module
Babel 官方的《Learn ES2015》則相對(duì)比較簡(jiǎn)略:
https://babeljs.io/learn-es2015/#ecmascript-2015-features-modules
http://es6-features.org/ 官方的介紹很簡(jiǎn)潔:
http://es6-features.org/#ValueExportImport
嚴(yán)格加載模式
ES6 的模塊自動(dòng)采用嚴(yán)格模式,不管你有沒有在模塊頭部加上"use strict"; 嚴(yán)格模式主要有以下限制:
- 變量必須聲明后再使用
- 函數(shù)的參數(shù)不能有同名屬性,否則報(bào)錯(cuò)
- 不能使用with語(yǔ)句
- 不能對(duì)只讀屬性賦值,否則報(bào)錯(cuò)
- 不能使用前綴0表示八進(jìn)制數(shù),否則報(bào)錯(cuò)
- 不能刪除不可刪除的屬性,否則報(bào)錯(cuò)
- 不能刪除變量delete prop,會(huì)報(bào)錯(cuò),只能刪除屬性delete global[prop]
- eval不會(huì)在它的外層作用域引入變量
- eval和arguments不能被重新賦值
- arguments不會(huì)自動(dòng)反映函數(shù)參數(shù)的變化
- 不能使用arguments.callee
- 不能使用arguments.caller
- 禁止this指向全局對(duì)象
- 不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧
- 增加了保留字(比如protected、static和interface)
export default 命令
下面兩行代碼的差別是,前者針對(duì)的是一個(gè) export default 的輸出,而后者則是一個(gè) export someName 這樣的輸出,在使用 import 的時(shí)候,后者需要使用「{}」符號(hào),前者不需要:
// 第一組
export default function () { // 輸出
// ...
}
import crc32 from './crc32'; // 輸入
// 第二組
export function crc32() { // 輸出
// ...
};
import {crc32} from './crc32'; // 輸入
如果想在一條import語(yǔ)句中,同時(shí)輸入默認(rèn)方法和其他變量,可以寫成下面這樣:
import lodash, { each } from 'lodash';
export 與 import 的復(fù)合寫法
export { foo, bar } from 'my_module';
// 等同于
import { foo, bar } from 'my_module';
export { foo, bar };
// 整體輸出
export * from 'my_module';
// 整體輸出默認(rèn)接口
export { default } from 'foo';
require()
require() is not part of your standard JavaScript. In context to your question and tags, require() is built into Node.js to load modules. The concept is similar to C/Java/Python/[insert more languages here] imports or includes.
瀏覽器上的不同加載方式
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
defer與async的區(qū)別是:前者要等到整個(gè)頁(yè)面正常渲染結(jié)束,才會(huì)執(zhí)行;后者一旦下載完,渲染引擎就會(huì)中斷渲染,執(zhí)行這個(gè)腳本以后,再繼續(xù)渲染。一句話,defer是“渲染完再執(zhí)行”,async是“下載完就執(zhí)行”。另外,如果有多個(gè)defer腳本,會(huì)按照它們?cè)陧?yè)面出現(xiàn)的順序加載,而多個(gè)async腳本是不能保證加載順序的。
瀏覽器加載 ES6 模塊,也使用<script>標(biāo)簽,但是要加入type="module"屬性。
<script type="module" src="foo.js"></script>
上面代碼在網(wǎng)頁(yè)中插入一個(gè)模塊foo.js,由于type屬性設(shè)為module,所以瀏覽器知道這是一個(gè) ES6 模塊。
瀏覽器對(duì)于帶有type="module"的<script>,都是異步加載,不會(huì)造成堵塞瀏覽器,即等到整個(gè)頁(yè)面渲染完,再執(zhí)行模塊腳本,等同于打開了<script>標(biāo)簽的defer屬性。
<script type="module" src="foo.js"></script>
<!-- 等同于 -->
<script type="module" src="foo.js" defer></script>
script 標(biāo)簽的async屬性也可以打開,這時(shí)只要加載完成,渲染引擎就會(huì)中斷渲染立即執(zhí)行。執(zhí)行完成后,再恢復(fù)渲染。
<script type="module" src="foo.js" async></script>
ES6 模塊也允許內(nèi)嵌在網(wǎng)頁(yè)中,語(yǔ)法行為與加載外部腳本完全一致。
<script type="module">
import utils from "./utils.js";
// other code
</script>
對(duì)于外部的模塊腳本(上例是foo.js),有幾點(diǎn)需要注意。
- 代碼是在模塊作用域之中運(yùn)行,而不是在全局作用域運(yùn)行。模塊內(nèi)部的頂層變量,外部不可見。
- 模塊腳本自動(dòng)采用嚴(yán)格模式,不管有沒有聲明use strict。
- 模塊之中,可以使用import命令加載其他模塊(.js后綴不可省略,需要提供絕對(duì) URL 或相對(duì) URL),也可以使用export命令輸出對(duì)外接口。
- 模塊之中,頂層的this關(guān)鍵字返回undefined,而不是指向window。也就是說,在模塊頂層使用this關(guān)鍵字,是無意義的。
- 同一個(gè)模塊如果加載多次,將只執(zhí)行一次。