這篇文章帶給大家的內容是關於ES6中模組Module的詳細介紹(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
這篇文章主要介紹了ES6新特性之模組Module用法,簡要說明了模組Module的概念、功能並結合實例形式分析了模組Module的使用方法與相關注意事項,需要的朋友可以參考下
一、Module簡介
ES6的Class只是物件導向程式設計的語法糖,升級了ES5的建構子的原型鏈繼承的寫法,並沒有解決模組化問題。 Module功能就是為了解決這個問題而提出的。
歷史上,JavaScript一直沒有模組(module)體系,無法將一個大程式拆分成互相依賴的小文件,再用簡單的方法拼裝起來。其他語言都有這項功能。
在ES6之前,社群制定了一些模組載入方案,最主要的有CommonJS和AMD兩種。前者用於伺服器,後者用於瀏覽器。 ES6在語言規格的層面上,實現了模組功能,而且實現得相當簡單,完全可以取代現有的CommonJS和AMD規範,成為瀏覽器和伺服器通用的模組解決方案。
ES6模組的設計思想,是盡量的靜態化,使得編譯時就能確定模組的依賴關係(這種載入稱為「編譯時載入」),以及輸入和輸出的變數。 CommonJS和AMD模組,都只能在運行時確定這些東西。
瀏覽器使用ES6模組的語法如下。
<script type="module" src="fs.js"></script>
上面程式碼在網頁中插入一個模組fs.js,由於type屬性設為module,所以瀏覽器知道這是一個ES6模組。
// ES6加载模块 import { stat, exists, readFile } from 'fs';
上面程式碼透過import去載入一個Module,載入其中的一些方法。
二、import 和 export
模組功能主要由兩個指令構成:export和import。 export指令用於規定模組的對外接口,import指令用於輸入其他模組提供的功能。
一個模組就是一個獨立的檔案。該文件內部的所有變量,外部無法取得。如果你希望外部能夠讀取模組內部的某個變量,就必須使用export關鍵字輸出該變數。下面是一個JS文件,裡面使用export指令輸出變數。
// profile.js export var firstName = 'Michael'; export var lastName = 'Jackson'; export var year = 1958;
export的寫法,除了像上面這樣,還有另外一種。 (推薦這種,因為這樣就可以在腳本尾部,一眼看清楚輸出了哪些變數。)
// profile.js var firstName = 'Michael'; var lastName = 'Jackson'; var year = 1958; export {firstName, lastName, year};
export指令除了輸出變數,還可以輸出函數或類別(class)。通常情況下,export輸出的變數就是原本的名字,但可以使用as關鍵字重新命名。
function v1() { ... } function v2() { ... } export { v1 as streamV1, v2 as streamV2, v2 as streamLatestVersion };
使用export指令定義了模組的對外介面以後,其他JS檔就可以透過import指令載入這個模組(檔)。
// main.js import {firstName, lastName, year} from './profile'; function setName(element) { element.textContent = firstName + ' ' + lastName; }
上面程式碼的import指令,就用來載入profile.js文件,並從中輸入變數。 import指令接受一個物件(用大括號表示),裡面指定要從其他模組匯入的變數名稱。大括號裡面的變數名,必須與被導入模組(profile.js)對外介面的名稱相同。
如果想為輸入的變數重新取一個名字,import指令要使用as關鍵字,將輸入的變數重新命名。
import { lastName as surname } from './profile';
import指令具有提升效果,會提升到整個模組的頭部,先執行。
foo(); import { foo } from 'my_module';
三、模組的整體加載
除了指定載入某個輸出值,還可以使用整體加載,也就是用星號(*)指定一個對象,所有輸出值都載入在這個物件上面。
有一個circle.js文件,它輸出兩個方法area和circumference。
現在,載入這個模組。
// main.js import { area, circumference } from './circle'; console.log('圆面积:' + area(4)); console.log('圆周长:' + circumference(14));
上面寫法是逐一指定要載入的方法,整體載入的寫法如下。
import * as circle from './circle'; console.log('圆面积:' + circle.area(4)); console.log('圆周长:' + circle.circumference(14));
為了提供使用者方便,讓他們不用閱讀文件就能載入模組,就要用到export default指令,為模組指定預設輸出。
// export-default.js export default function () { console.log('foo'); }
上面程式碼是一個模組檔案export-default.js,它的預設輸出是一個函數。
其他模組載入該模組時,import指令可以為該匿名函數指定任意名字。
// import-default.js import customName from './export-default'; customName(); // 'foo'
要注意的是,這時import指令後面,不使用大括號。
本質上,export default就是輸出一個叫做default的變數或方法,然後系統允許你為它取任意名字。它後面不能跟變數宣告語句。
// 正确 var a = 1; export default a; // 错误 export default var a = 1;
五、ES6模組載入的實質
ES6模組載入的機制,與CommonJS模組完全不同。 CommonJS模組輸出的是一個值的拷貝,而ES6模組輸出的是值的參考。
CommonJS模組輸出的是被輸出值的拷貝,也就是說,一旦輸出一個值,模組內部的變化就會影響不到這個值。請看下面這個模組檔案lib.js的範例。
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, };
上面程式碼輸出內部變數counter和改寫這個變數的內部方法incCounter。然後,在main.js裡面載入這個模組。
// main.js var mod = require('./lib'); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // 3
上面代码说明,lib.js模块加载以后,它的内部变化就影响不到输出的mod.counter了。这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { get counter() { return counter }, incCounter: incCounter, };
上面代码中,输出的counter属性实际上是一个取值器函数。现在再执行main.js,就可以正确读取内部变量counter的变动了。
ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个动态的只读引用。等到真的需要用到时,再到模块里面去取值,换句话说,ES6的输入有点像Unix系统的“符号连接”,原始值变了,import输入的值也会跟着变。因此,ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
还是举上面的例子。
// lib.js export let counter = 3; export function incCounter() { counter++; } // main.js import { counter, incCounter } from './lib'; console.log(counter); // 3 incCounter(); console.log(counter); // 4
上面代码说明,ES6模块输入的变量counter是活的,完全反应其所在模块lib.js内部的变化。
由于ES6输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。
// lib.js export let obj = {}; // main.js import { obj } from './lib'; obj.prop = 123; // OK obj = {}; // TypeError
上面代码中,main.js从lib.js输入变量obj,可以对obj添加属性,但是重新赋值就会报错。因为变量obj指向的地址是只读的,不能重新赋值,这就好比main.js创造了一个名为obj的const变量。
最后,export通过接口,输出的是同一个值。不同的脚本加载这个接口,得到的都是同样的实例。
// mod.js function C() { this.sum = 0; this.add = function () { this.sum += 1; }; this.show = function () { console.log(this.sum); }; } export let c = new C();
上面的脚本mod.js,输出的是一个C的实例。不同的脚本加载这个模块,得到的都是同一个实例。
// x.js import {c} from './mod'; c.add(); // y.js import {c} from './mod'; c.show(); // main.js import './x'; import './y';
现在执行main.js,输出的是1。这就证明了x.js和y.js加载的都是C的同一个实例。
以上是ES6中模組Module的詳細介紹(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!