深入ES6 模塊系統

来源:http://www.cnblogs.com/wwhhq/archive/2017/12/21/8080824.html
-Advertisement-
Play Games

深入ES6 模塊系統 本文轉載自: "眾成翻譯" 譯者: "neck" 鏈接: "http://www.zcfy.cc/article/4436" 原文: "https://ponyfoo.com/articles/es6 modules in depth the es6 module system ...


深入ES6 模塊系統

本文轉載自:眾成翻譯
譯者:neck
鏈接:http://www.zcfy.cc/article/4436
原文:https://ponyfoo.com/articles/es6-modules-in-depth#the-es6-module-system

ES6 模塊系統

在ES6之前,我們用自己的方式來在 JavaScript 中實現模塊。很長一段時間以來,像 RequireJS、Angular 的依賴註入和 CommonJS 這樣的系統,配合著一些有用的工具,比如 Browserify 和 Webpack,一直在解決我們的需求。然而,到了2015 年,一個標準的模塊系統早就應該發佈了。我們馬上就會看到,你很快會註意到 ES6 模塊受到了 CommonJS 的很大影響。我們將查看exportimport語句,從中會看到ES6模塊和CommonJS有多一致,同時,我們將會在這篇文章中討論它們。

今天我們將介紹 ES6 模塊系統的幾個方面。

嚴格模式

在 ES6 模塊系統中, 嚴格模式預設被開啟。如果你不知道嚴格模式是什麼, 它只是語言的一個更嚴格的版本它讓語言的很多不好的部分都消失了。它使編譯器可以通過在用戶代碼中禁止使用一些不可靠的語法來表現得更好。下麵是對 MDN 上的嚴格模式文章中所記錄的更改的總結。

  • 變數不能未聲明就使用

  • 函數參數必須有唯一的名稱 (否則會被認為是語法錯誤)

  • with 語句被禁止使用

  • 賦值給只讀屬性會拋出一個錯誤

  • 00840 這樣的八進位數是語法錯誤

  • 嘗試 delete 不可刪除的數據會拋出一個錯誤

  • delete prop 被認為是語法錯誤, 只能刪除屬性 delete global[prop]

  • eval 不會引入新的變數到它的作用域

  • evalarguments 的綁定不會被改變

  • arguments 不會神奇地跟蹤方法參數的變化

  • 不再支持arguments.callee,使用它會拋出 TypeError

  • 不再支持arguments.caller,使用它會拋出 TypeError

  • 上下文作為 this 在方法調用時不會被強制包裝成一個 Object(譯者註:即this不會指向全局對象)

  • 不再能夠使用 fn.caller and fn.arguments 訪問 JavaScript 的堆棧

  • 保留字(例如 protected, static, interface等等)不能被作為新變數聲明

如果這些規則對你來說不是顯而易見的,你應該使用 'use strict' 在每一個地方。儘管在 ES6 中已經成為事實,但在 ES6 中使用 'use strict' 仍然是一種很好的做法。我已經使用嚴格模式很長時間了,並且絕不會用回原來的模式!

現在讓我們瞭解export,我們的第一個 ES6 模塊關鍵字!

export

在 CommonJS 中,你將值暴露在module.exports上來導出它們。正如下麵的代碼片段所示,您可以導出任何內容像是基本類型、對象、數組或函數。

module.exports = 1
module.exports = NaN
module.exports = 'foo'
module.exports = { foo: 'bar' }
module.exports = ['foo', 'bar']
module.exports = function foo () {}

ES6模塊系統將 export封裝成API,類似於 CommonJS的modules。ES6 模塊中的聲明只作用於該模塊,和使用 CommonJS 一樣。這意味著,在模塊中聲明的任何變數都不能用於其他模塊,除非它們明確地導出為模塊 API 的一部分(然後導入到希望訪問它們的模塊中)。

導出預設的綁定

你可以通過把 module.exports = 變成 export default來模擬我們剛剛看到的CommonJS代碼。

export default 1
export default NaN
export default 'foo'
export default { foo: 'bar' }
export default ['foo', 'bar']
export default function foo () {}

與 CommonJS 不同,導出語句只能放在 ES6 模塊的最外層,而不能放在方法中,即使在載入模塊時它們所在的方法會立即被調用。據推測,這種限制是為了讓編譯器更容易地解釋 ES6 模塊,但是這也是一個很好的限制,因為有很多很好的理由去以動態地定義和暴露 API的方式來調用方法。

function foo () {
  export default 'bar' // SyntaxError
}
foo()

你不只可以使用預設的Export,你還可以使用具名的Exports。

具名的Exports

在 CommonJS 中,你甚至不需要事先分配一個對象給 module.exports。你可以把屬性添加到它上面。不管 module.exports最終的屬性包含什麼,它仍然是一個單獨的綁定。

module.exports.foo = 'bar'
module.exports.baz = 'ponyfoo'

我們可以通過使用具名導出語法在 ES6 模塊中複製上述內容,而不是像CommonJS一樣將它分配給module.exports。在ES6中,你可以聲明要export的綁定。註意,下麵的代碼不能重構為先聲明變數再執行 export foo,那將會導致一個語法錯誤。在這裡,我們看到了ES6模塊如何通過聲明式模塊系統API的工作方式來支持靜態分析。

export var foo = 'bar'
export var baz = 'ponyfoo'

還有一個重要的點,是要記住我們正在導出的是綁定。

是綁定,而不是值

重要的一點是,ES6 模塊導出的是綁定,而不是值或引用。這意味著您導出的foo 變數將被綁定到模塊上的foo 變數中,它的值將取決於對foo的修改。 不過,我建議在最初載入模塊之後,不要更改模塊的公共介面。

如果你有一個./a模塊像下麵這樣,這導出的foo將被綁定為'bar',持續500ms之後,foo將綁定為 'baz'

export var foo = 'bar'
setTimeout(() => foo = 'baz', 500)

除了預設綁定和單獨綁定之外,你還可以導出一個綁定列表。

綁定列表

正如下麵的代碼片段所示,ES6 模塊允許你導出已命名的位於頂級作用域的成員列表。

var foo = 'ponyfoo'
var bar = 'baz'
export { foo, bar }

如果你想要用其他名字來導出一個綁定,你可以使用export { foo as bar }語句,就像下麵展示的這樣。

`export { foo as ponyfoo }`

在使用export的命名成員列表聲明風格時,還可以使用as default 。下麵代碼的作用和執行export default fooexport bar 一樣,只不過在一行語句而已。

`export { foo as default, bar }`

只在模塊文件的底部使用export default有很多好處。

export最佳實踐

可以定義具名的Exports,可以導出一個具有別名的列表,還可以暴露一個預設的export,這會導致一些混亂。在很大程度上,我鼓勵你們使用export default並且最好在模塊文件的末尾使用。如下代碼所示,你可以調用你的API 對象 api 或者將它命名為模塊本身。

var api = {
  foo: 'bar',
  baz: 'ponyfoo'
}
export default api

第一,模塊的導出介面立即變得明顯。無需在模塊中翻查並將各個部分組合在一起來計算 API,您只需滾動到最後。有一個清晰定義的 API 導出的地方,也可以更容易地解釋模塊導出的方法和屬性。
第二,是應該使用 export default還是具名的導出又或者是列表的導出甚至是帶有別名的導出,你不應該糾結這個。現在有一個指導方針,就是在任何地方都使用 export default
第三,一致性。 在CommonJS世界中,我們通常從模塊中導出一個方法,然後就可以了。而使用具名導出進行這樣的操作是不可能的,因為你暴露了一個對象來表示該方法,除非你在導出列表中使用as default
第四,這實際上是之前所提到的點的總結。export default 語句放在模塊的底部,我們立即可以很清晰的看出這個模塊的API是什麼、有哪些方法,可以讓模塊的使用者可以很輕鬆的調用它的 API。當習慣於使用export default並總是在模塊的最後使用它,你會感到使用ES6的模塊系統是無痛的。
現在我們已經討論了export API 及其註意事項,讓我們開始討論 import 語句。

import

這個語句是和export相對的語句。首先,它們可以被用來從另一個模塊載入一個模塊,這種載入模塊的方式是特別實現的,目前還沒有瀏覽器實現模塊載入。聰明的人會在瀏覽器中解決模塊載入問題,這樣,你就可以立即編寫符合標準的 ES6 代碼。像 Babel 這樣的轉換工具可以在模塊系統的幫助下像CommonJS一樣連接模塊。意味著在babel中,import語句和CommonJS中的require語句遵循一樣的語義。

讓我們以 lodash 為例。下麵的語句簡單地從模塊中載入 Lodash 模塊。它並沒有創建任何變數,但它將可以使用lodash 模塊。

`import 'lodash'`

在導入綁定之前,讓我們來關註一下import 語句的實際情況。和export 很像,它只能定義在模塊的頂級作用域。這可以幫助轉換工具實現它們的模塊載入功能,並幫助其它靜態分析工具解析你的代碼庫。

導入預設的Exports

在CommonJS中,你可以通過 require語句import一些代碼,就像這樣:

`var _ = require('lodash')`

要從ES6模塊導入預設的導出綁定,你只需要為它指定一個名字。與聲明一個變數相比,語法有點不同,因為你正在導入一個綁定,而且可以讓它更利於靜態分析工具的分析。

`import _ from 'lodash'`

你也可以導入具名的導出並且可以使用別名。

導入具名的導出

這裡的語法和我們剛纔使用的預設導出非常相似,只需添加一些大括弧,然後選擇任意指定的導出. 註意,這個語法類似於解構賦值語法,但也有一些不同。

`import {map, reduce} from 'lodash'`

不同於解構賦值的是,你可以使用別名來重命名導入的綁定。你可以在你認為合適的情況下混合使用別名和非別名的導出。

`import {cloneDeep as clone, map} from 'lodash'`

你還可以混合和匹配指定的導出和預設導出。如果你想要它在括弧里,你必須使用default的名稱,你可以為default指定別名;或者你也可以將預設的導入與指定的導入列表混合在一起。

import {default, map} from 'lodash'
import {default as _, map} from 'lodash'
import _, {map} from 'lodash'

最後,還有import *的語句

import 所有內容

你還可以將一個模塊導入為命名空間對象。它不導入指定的導出或預設值,而是導入所有的東西。註意,導入語法必須使用別名,其中所有綁定都將被替換到別名上。如果有一個預設的導出,將會被替換為alias.default

`import * as _ from 'lodash'`

上面的代碼展示了這個語法。

結論

註意,你可以在利用CommonJS模塊的同時,通過babel編譯器來使用ES6模塊。最重要的是,你可以在CommonJS和ES6模塊之間進行互操作。這意味著即使你導入了一個用CommonJs編寫的模塊,它也會起作用。
ES6模塊系統看起來很棒,它是JavaScript中缺少的最重要的東西之一。我希望他們能很快找到一個最終完成的模塊載入API和瀏覽器實現。你可以從一個模塊中exportimport綁定的多種方法,但這並不多,因為它們增加了複雜性,但是時間將會告訴你,所有額外的API是否和它的龐大一樣方便。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在我們平時做的很多網站項目中都會需要繪製各種各樣的二維矢量圖形。比如做城市地下管網的斷面圖、管線管點的坐標位置矢量標識圖、鑽孔位置或地層剖面圖等等。我們有很多種方法來繪製這些矢量圖(vml、canvas、svg等等),下麵我要介紹的是SVG繪圖語言,也是我在做項目中用到比較多的,僅以我的個人實戰經驗 ...
  • zTree 優秀的jquery樹插件,文檔詳細,渲染快 使用方法: 1、引用zTree的js和css文件 2、ztree的html為 需加Class:ztree; 3、初始化樹 後臺介面返回數據示例: 4、加入滑鼠移動到顯示的自定義按鈕 5、文檔地址 http://www.treejs.cn/v3/ ...
  • 自從ES6流行起來,Promise 的使用變得更頻繁更廣泛了,比如非同步請求一般返回一個 Promise 對象,Generator 中 yield 後面一般跟 Promise 對象,ES7中 Async 函數中 await 後面一般也是 Promise 對象,還有更多的 NodeAPI 也會返回 Pr ...
  • 如果覺得設置樣式太麻煩,或者頁面上選中的樣式太複雜,也可以用背景圖去修改樣式<div class=""> <label><input type="radio" name="1"><i class="spot"></i>123456</label> <label><input type="radio" ...
  • 近年來,前端技術的發展迅速,但因為前端知識面龐大,在實際學習當中往往無法理清其中的脈絡。下麵從各種庫、框架、插件的層面上,對前端知識點做一些簡單的梳理。從軟體工程上,將前端分為四個由淺及深的層面或階段。 一、基礎層(瀏覽器原生支持html/css/js) HTML超文本標記語言,用標簽構建網頁的內容 ...
  • 總體過了一下後面的流程,發現Compiler模塊確實不適合單獨講解,這裡繼續講解後面的代碼: 這行代碼與之前設置options預設值非常相似,但是複雜程度根本不是一個次元的。 這一節只能簡單的看一眼內部到底有多少東西,整理後源碼如下: 這個模塊除去父類引入,其餘插件光頂部引入就有34個,簡直就是插件 ...
  • openlayers3教材詳解及demo(完整) OpenLayers 3對OpenLayers網路地圖庫進行了根本的重新設計。版本2雖然被廣泛使用,但從JavaScript開發的早期發展階段開始,已日益現實出它的落後。 OL3已運用現代的設計模式從底層重寫。 最初的版本旨在支持第2版提供的功能,提 ...
  • HTML5 var uaTest = /Android|webOS|Windows Phone|iPhone|ucweb|ucbrowser|iPod|iPad|BlackBerry/i.test(navigator.userAgent.toLowerCase());var touchTest = ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...