快速使用Romanysoft LAB的技術實現 HTML 開發Mac OS App,並銷售到蘋果應用商店中。《HTML開發Mac OS App 視頻教程》
- 土豆網同步更新:http://www.tudou.com/plcover/VHNh6ZopQ4E/
- 百度網盤同步:http://pan.baidu.com/s/1jG1Q58M
- 分享 [中文紀錄片]互聯網時代 http://pan.baidu.com/s/1qWkJfcS
官方QQ羣:(申請加入,說是我推薦的)
在任何一個大型應用中模塊化是很常見的。ES6的模塊爲JavaScript提供了這個特性,而且爲這些模塊提供了許多選擇方法來導出和引入對象。Ravi Kiran 在《 Modules in ECMAScript 6 (ES6) 》一文中主要討論了ES6模塊系統。如下爲該文章的簡譯內容:javascript
不管使用何種編程語言開發大型應用,最關鍵的特性就是代碼模塊化。這個概念在不一樣的編程語言裏有着不一樣的命名,在C裏爲頭部文件,C++和C#裏爲命名空間,Java中爲包,名稱不同但解決的是同一問題。正如《 ECMAScript 6 – New language improvements in JavaScript 》系列文章中第一篇所提到的那樣,最初JavaScript並非用來編寫大量代碼的,好比建立大型框架、App應用等。就在咱們由於JavaScript缺乏對模塊的支持而編寫大量代碼時,開源開發者提出了一些標準,如CommoneJs模塊模型、異步模塊定義(AMD)以及一些庫,來實現模塊化。在過去幾年裏,這些庫得到了普遍關注,併成功應用到多個企業規模級的應用程序中。php
ES6爲JavaScript帶來了模塊特性。瀏覽器實現這一特性還須要一段時間,由於它們必須定義一個方法來動態下載文件。在瀏覽器支持該特性之前,咱們可使用編譯器,如 Traceur、6to五、ES6 Module Loader以及其它可讓ES6模塊轉換成ES5的轉碼器。css
JavaScript模塊系統的現狀java
CommonJS模塊系統python
CommonJs是一個由開源開發者組成的團隊,主要圍繞JavaScript實現一些API及開展研發實踐。該團隊提出了一個JavaScript模塊規範。每一個文件均可看成一個模塊,而且每一個文件能夠訪問兩個對象:require和export。require用來接收字符串(模塊名),並返回該模塊輸出的對象。export對象用來導出該模塊的方法和變量。require方法返回的就是export對象。模塊同步加載。服務器端JavaScript引擎Node.js就是用的這個模塊系統。sql
異步模塊定義(AMD)npm
AMD是一個採用異步方式加載依賴模塊的模塊系統。若是模塊在不一樣文件中,它們將採用XHR進行加載。某一模塊將等其所依賴的模塊一一加載後纔會被執行。AMD模塊必須是一個函數,並做爲參數傳入define函數中。函數的返回值將傳輸給全部依賴的模塊,所得到返回值又將做爲參數傳給模塊方法。Require.js庫中實現了AMD。編程
TypeScript模塊瀏覽器
TypeScript,做爲JavaScript的超集,也提供了一個模塊系統。當它被編譯時,便開始使用JavaScript模塊模式。TypeScript模塊使用module關鍵字定義,任何被輸出的對象必須使用export關鍵字定義。import關鍵字用來將其它模塊加載入模塊中,並捕捉該模塊導出的對象。TypeScript模塊是同步加載的。服務器
ES6模塊系統
ES6模塊系統啓發於上述現有模塊系統,它具備如下特性:
接下來讓咱們經過具體編程方法看看每個特性。
導出對象
在現有的模塊系統中,每一個JavaScript代碼文件在ES6中都是一個模塊。只有模塊中的對象須要被外部調用時,模塊纔會輸出對象,其他則都是模塊的私有對象。該處理方式將細節進行封裝,僅導出必要的功能。
從模塊裏導出對象,ES6爲咱們提供了不一樣方法,見下面的討論。
內聯導出
ES6模塊裏的對象可在建立它們的聲明中導出。一個模塊中可無數次使用export,全部的對象將被一塊兒導出。請看下面的例子:
export class Employee{ constructor(id, name, dob){ this.id = id; this.name=name; this.dob= dob; } getAge(){ return (new Date()).getYear() - this.dob.getYear(); } } export function getEmployee(id, name, dob){ return new Employee(id, name, dob); } var emp = new Employee(1, "Rina", new Date(1987, 1, 22));
案例中的模塊導出了兩個對象: Employee類,getEmployee函數。因對象emp未被導出,因此其仍爲模塊私有。
導出一組對象
儘管內聯導出頗有效,但在大規模模塊中,它就很難發揮做用了,由於咱們可能沒法追蹤到模塊導出來的對象。在這種狀況下,更好的辦法是,在模塊的末尾單獨進行導出聲明,以導出該模塊中的所有對象。
使用單獨導出聲明重寫上一案例中的模塊,結果以下:
class Employee{ constructor(id, name, dob){ this.id = id; this.name=name; this.dob= dob; } getAge(){ return (new Date()).getYear() - this.dob.getYear(); } } function getEmployee(id, name, dob){ return new Employee(id, name, dob); } var x = new Employee(1, "Rina", new Date(1987, 1, 22)); export {Employee, getEmployee};
在導出時,重命名對象也是能夠的。以下例所示,Employee在導出時名字改成了Associate,函數GetEmployee更名爲getAssociate。
export {
Associate as Employee, getAssociate as getEmployee };
Default導出
使用關鍵字default,可將對象標註爲default對象導出。default關鍵字在每個模塊中只能使用一次。它既能夠用於內聯導出,也能夠用於一組對象導出聲明中。
下面案例展現了在組導出語句中使用default:
export default { Employee, getEmployee };
導入模塊
現有模塊可使用關鍵字import導入到其它模塊。一個模塊能夠被導入任意數量的模塊中。下文展現了導入模塊的不一樣方式。
無對象導入
若是模塊包含一些邏輯要執行,且不會導出任何對象,此類對象也能夠被導入到另外一模塊中。以下面案例所示:
import './module1.js';
導入默認對象
採用Default導出方式導出對象,該對象在import聲明中將直接被分配給某個引用,以下例中的「d」。
import d from './module1.js';
導入命名的對象
正如以上討論的,一個模塊能夠導出許多命名對象。若是另外一模塊想導入這些命名對象,須要在導入聲明中一一列出這些對象。舉個例子:
import {Employee, getEmployee} from './module1.js';
固然也可在同一個聲明中導入默認對象和命名對象。這種狀況下,默認對象必須定義一個別名,以下例。
import {default as d, Employee} from './module1.js';
導入全部對象
以上幾種狀況,只有import聲明中列舉的對象纔會被導入並被使用,而其它對象則沒法在導入模塊中使用。固然,這就要求用戶瞭解哪些對象能夠導出並加以利用。若是模塊導出大量對象,另外一模塊想引入全部導出的對象,就必須使用以下聲明:
import * as allFromModule1 from './module1.js';
allFromModule1這一別名將指向全部從module1導出的對象。在導入模塊中,它們做爲屬性可被訪問。
可編程式的按需導入
若是想基於某些條件或等某個事件發生後再加載須要的模塊,可經過使用加載模塊的可編程API(programmatic API)來實現。使用System.import方法,可按程序設定加載模塊。這是一個異步的方法,並返回Promise。
該方法的語法示例以下:
System.import('./module1.js') .then(function(module1){ //use module1 }, function(e){ //handle error });
若是模塊加載成功且將導出的模塊成功傳遞給回調函數,Promise將會經過。若是模塊名稱有誤或因爲網絡延遲等緣由致使模塊加載失敗,Promise將會失敗。
ES6模塊使用現狀
到目前爲止,全部瀏覽器還不能天然支持ES6模塊,因此在瀏覽器加載以前,咱們須要使用轉譯器(transpiler)將代碼轉換成ES5。直到如今,我一直使用Traceur做爲個人轉譯器,建議你們使用相同的工具將模塊代碼轉化爲瀏覽器可識別的代碼。讓咱們看看編譯ES6模塊的幾種不一樣的方法。
使用Traceur動態編譯ES6模塊
當瀏覽器加載腳本後,咱們可使用Traceur的客戶端庫動態編譯ES6模塊。使用該方法,運行模塊無需運行任何命令。咱們要作得就是,在頁面上加載Traceur庫,及添加代碼腳原本運行WebPageTranscoder。
<script> new traceur.WebPageTranscoder(document.location.href).run(); </script>
如今,咱們就能夠在script標籤內,將類型指定成模塊,以此導入任何一個ES6文件。
<script type="module"> import './modules/import1.js'; </script>
類型指定爲模塊的任何腳本標籤將被ES6客戶端庫獲取並處理。上面代碼塊中的導入語句將發送AJAX請求,捕獲相應的JavaScript文件,並載入它。若是模塊內部引用了另外一個模塊,單獨的AJAX請求將發出,以加載與引用模塊相對應的文件。
使用Traceur命令編譯ES6模塊
使用Traceur命令能夠將ES6模塊編譯成AMD或者CommonJS模塊。這個方法有兩大優勢。
爲了使用編譯完成的AMD/CommonJs的模塊,咱們須要包含支持模塊系統的庫。我我的比較傾向AMD,因此我將在這裏介紹一下它。CommonJS模塊的步驟和這個差很少。
下面這句命令是用來讓包含ES6模塊的文件夾編譯成AMD,並把它們存儲在一個單獨的文件夾:
traceur --dir modules es5Modules --modules=amd
使用CommonJs,你須要在上面命令中使用commonjs代替modules。
在這裏,modules指的是包含ES6的文件夾,es5Modules指的是輸出目錄。若是查看es5Modules文件夾下的任何文件,你將看到該AMD定義塊。require.js支持AMD,因此咱們能夠在HTML頁面中,使用script引入require.js,並用data-main屬性指明開始文件,就像下面這樣:
<script src="bower_components/requirejs/require.js" data-main="es5Modules/import2.js"></script>
使用Traceur Grunt Task編譯ES6模塊
使用命令編譯模塊很累並且更容易出錯。咱們可使用grunt-traceur自動化編譯過程。此時,你須要安裝NPM包。
npm intall grunt-traceur –save
Grunt任務所需數據與提供給命令的數據同樣。下面是任務的一些配置:
traceur: { options: { modules: "amd" }, custom: { files: [{ expand: true, cwd: 'modules', src: ['*.js'], dest: 'es5Modules' }] } }
如今你能夠在控制檯裏使用下面的命令來運行上面的Grunt任務:
grunt traceur
正如你所看見的那樣,它和咱們使用命令所產生的效果是同樣的。
結論
任何一個大型應用中,模塊化十分必要。ES6模塊爲JavaScript提供了該特性,這些模塊提供了衆多選擇來導出和引入對象。我很期待該特性被瀏覽器支持的那一天,到時咱們無需加載任何第三方庫便可建立、加載JavaScript模塊。目前流行的客戶端MV*框架Angular.js在其2.0版本(目前還在開發中)中就使用了ES6的模塊化。
讓咱們開始使用模塊系統,從而讓咱們的代碼更具組織和可讀性。