學(xué)習(xí)筆記《ES6 的模塊加載》

一些資料

阮一峰的《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í)行一次。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容