ES6新特性之模塊Module用法詳解
本文實(shí)例講述了ES6新特性之模塊Module用法。分享給大家供大家參考,具體如下:
一、Module簡(jiǎn)介
ES6的Class只是面向?qū)ο缶幊痰恼Z(yǔ)法糖,升級(jí)了ES5的構(gòu)造函數(shù)的原型鏈繼承的寫法,并沒(méi)有解決模塊化問(wèn)題。Module功能就是為了解決這個(gè)問(wèn)題而提出的。
歷史上,JavaScript一直沒(méi)有模塊(module)體系,無(wú)法將一個(gè)大程序拆分成互相依賴的小文件,再用簡(jiǎn)單的方法拼裝起來(lái)。其他語(yǔ)言都有這項(xiàng)功能。
在ES6之前,社區(qū)制定了一些模塊加載方案,最主要的有CommonJS和AMD兩種。前者用于服務(wù)器,后者用于瀏覽器。ES6在語(yǔ)言規(guī)格的層面上,實(shí)現(xiàn)了模塊功能,而且實(shí)現(xiàn)得相當(dāng)簡(jiǎn)單,完全可以取代現(xiàn)有的CommonJS和AMD規(guī)范,成為瀏覽器和服務(wù)器通用的模塊解決方案。
ES6模塊的設(shè)計(jì)思想,是盡量的靜態(tài)化,使得編譯時(shí)就能確定模塊的依賴關(guān)系(這種加載稱為“編譯時(shí)加載”),以及輸入和輸出的變量。CommonJS和AMD模塊,都只能在運(yùn)行時(shí)確定這些東西。
瀏覽器使用ES6模塊的語(yǔ)法如下。
<script type="module" src="fs.js"></script>
上面代碼在網(wǎng)頁(yè)中插入一個(gè)模塊fs.js,由于type屬性設(shè)為module,所以瀏覽器知道這是一個(gè)ES6模塊。
// ES6加載模塊 import { stat, exists, readFile } from 'fs';
上面代碼通過(guò)import去加載一個(gè)Module,加載其中的一些方法。
二、import 和 export
模塊功能主要由兩個(gè)命令構(gòu)成:export和import。export命令用于規(guī)定模塊的對(duì)外接口,import命令用于輸入其他模塊提供的功能。
一個(gè)模塊就是一個(gè)獨(dú)立的文件。該文件內(nèi)部的所有變量,外部無(wú)法獲取。如果你希望外部能夠讀取模塊內(nèi)部的某個(gè)變量,就必須使用export關(guān)鍵字輸出該變量。下面是一個(gè)JS文件,里面使用export命令輸出變量。
// profile.js export var firstName = 'Michael'; export var lastName = 'Jackson'; export var year = 1958;
export的寫法,除了像上面這樣,還有另外一種。(推薦這種,因?yàn)檫@樣就可以在腳本尾部,一眼看清楚輸出了哪些變量。)
// profile.js var firstName = 'Michael'; var lastName = 'Jackson'; var year = 1958; export {firstName, lastName, year};
export命令除了輸出變量,還可以輸出函數(shù)或類(class)。通常情況下,export輸出的變量就是本來(lái)的名字,但是可以使用as關(guān)鍵字重命名。
function v1() { ... } function v2() { ... } export { v1 as streamV1, v2 as streamV2, v2 as streamLatestVersion };
使用export命令定義了模塊的對(duì)外接口以后,其他JS文件就可以通過(guò)import命令加載這個(gè)模塊(文件)。
// main.js import {firstName, lastName, year} from './profile'; function setName(element) { element.textContent = firstName + ' ' + lastName; }
上面代碼的import命令,就用于加載profile.js文件,并從中輸入變量。import命令接受一個(gè)對(duì)象(用大括號(hào)表示),里面指定要從其他模塊導(dǎo)入的變量名。大括號(hào)里面的變量名,必須與被導(dǎo)入模塊(profile.js)對(duì)外接口的名稱相同。
如果想為輸入的變量重新取一個(gè)名字,import命令要使用as關(guān)鍵字,將輸入的變量重命名。
import { lastName as surname } from './profile';
import命令具有提升效果,會(huì)提升到整個(gè)模塊的頭部,首先執(zhí)行。
foo(); import { foo } from 'my_module';
三、模塊的整體加載
除了指定加載某個(gè)輸出值,還可以使用整體加載,即用星號(hào)(*)指定一個(gè)對(duì)象,所有輸出值都加載在這個(gè)對(duì)象上面。
有一個(gè)circle.js文件,它輸出兩個(gè)方法area和circumference。
現(xiàn)在,加載這個(gè)模塊。
// main.js import { area, circumference } from './circle'; console.log('圓面積:' + area(4)); console.log('圓周長(zhǎng):' + circumference(14));
上面寫法是逐一指定要加載的方法,整體加載的寫法如下。
import * as circle from './circle'; console.log('圓面積:' + circle.area(4)); console.log('圓周長(zhǎng):' + circle.circumference(14));
四、export default
為了給用戶提供方便,讓他們不用閱讀文檔就能加載模塊,就要用到export default命令,為模塊指定默認(rèn)輸出。
// export-default.js export default function () { console.log('foo'); }
上面代碼是一個(gè)模塊文件export-default.js,它的默認(rèn)輸出是一個(gè)函數(shù)。
其他模塊加載該模塊時(shí),import命令可以為該匿名函數(shù)指定任意名字。
// import-default.js import customName from './export-default'; customName(); // 'foo'
需要注意的是,這時(shí)import命令后面,不使用大括號(hào)。
本質(zhì)上,export default就是輸出一個(gè)叫做default的變量或方法,然后系統(tǒng)允許你為它取任意名字。它后面不能跟變量聲明語(yǔ)句。
// 正確 var a = 1; export default a; // 錯(cuò)誤 export default var a = 1;
五、ES6模塊加載的實(shí)質(zhì)
ES6模塊加載的機(jī)制,與CommonJS模塊完全不同。CommonJS模塊輸出的是一個(gè)值的拷貝,而ES6模塊輸出的是值的引用。
CommonJS模塊輸出的是被輸出值的拷貝,也就是說(shuō),一旦輸出一個(gè)值,模塊內(nèi)部的變化就影響不到這個(gè)值。請(qǐng)看下面這個(gè)模塊文件lib.js的例子。
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, };
上面代碼輸出內(nèi)部變量counter和改寫這個(gè)變量的內(nèi)部方法incCounter。然后,在main.js里面加載這個(gè)模塊。
// main.js var mod = require('./lib'); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // 3
上面代碼說(shuō)明,lib.js模塊加載以后,它的內(nèi)部變化就影響不到輸出的mod.counter了。這是因?yàn)閙od.counter是一個(gè)原始類型的值,會(huì)被緩存。除非寫成一個(gè)函數(shù),才能得到內(nèi)部變動(dòng)后的值。
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { get counter() { return counter }, incCounter: incCounter, };
上面代碼中,輸出的counter屬性實(shí)際上是一個(gè)取值器函數(shù)。現(xiàn)在再執(zhí)行main.js,就可以正確讀取內(nèi)部變量counter的變動(dòng)了。
ES6模塊的運(yùn)行機(jī)制與CommonJS不一樣,它遇到模塊加載命令import時(shí),不會(huì)去執(zhí)行模塊,而是只生成一個(gè)動(dòng)態(tài)的只讀引用。等到真的需要用到時(shí),再到模塊里面去取值,換句話說(shuō),ES6的輸入有點(diǎn)像Unix系統(tǒng)的“符號(hào)連接”,原始值變了,import輸入的值也會(huì)跟著變。因此,ES6模塊是動(dòng)態(tài)引用,并且不會(huì)緩存值,模塊里面的變量綁定其所在的模塊。
還是舉上面的例子。
// 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
上面代碼說(shuō)明,ES6模塊輸入的變量counter是活的,完全反應(yīng)其所在模塊lib.js內(nèi)部的變化。
由于ES6輸入的模塊變量,只是一個(gè)“符號(hào)連接”,所以這個(gè)變量是只讀的,對(duì)它進(jìn)行重新賦值會(huì)報(bào)錯(cuò)。
// lib.js export let obj = {}; // main.js import { obj } from './lib'; obj.prop = 123; // OK obj = {}; // TypeError
上面代碼中,main.js從lib.js輸入變量obj,可以對(duì)obj添加屬性,但是重新賦值就會(huì)報(bào)錯(cuò)。因?yàn)樽兞縪bj指向的地址是只讀的,不能重新賦值,這就好比main.js創(chuàng)造了一個(gè)名為obj的const變量。
最后,export通過(guò)接口,輸出的是同一個(gè)值。不同的腳本加載這個(gè)接口,得到的都是同樣的實(shí)例。
// 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,輸出的是一個(gè)C的實(shí)例。不同的腳本加載這個(gè)模塊,得到的都是同一個(gè)實(shí)例。
// x.js import {c} from './mod'; c.add(); // y.js import {c} from './mod'; c.show(); // main.js import './x'; import './y';
現(xiàn)在執(zhí)行main.js,輸出的是1。這就證明了x.js和y.js加載的都是C的同一個(gè)實(shí)例。
希望本文所述對(duì)大家ECMAScript程序設(shè)計(jì)有所幫助。
相關(guān)文章
微信小程序動(dòng)態(tài)顯示項(xiàng)目倒計(jì)時(shí)效果
這篇文章主要為大家詳細(xì)介紹了微信小程序動(dòng)態(tài)顯示項(xiàng)目倒計(jì)時(shí),格式如4天7小時(shí)58分鐘39秒,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06用js來(lái)刷新當(dāng)前頁(yè)面保留參數(shù)的具體實(shí)現(xiàn)
本文為大家詳細(xì)介紹下如何使用js來(lái)刷新當(dāng)前頁(yè)面保留參數(shù),下面有個(gè)不錯(cuò)的實(shí)現(xiàn)大家可以看看2013-12-12JavaScript實(shí)現(xiàn)班級(jí)隨機(jī)點(diǎn)名小應(yīng)用需求的具體分析
班級(jí)隨機(jī)點(diǎn)名小應(yīng)用,點(diǎn)擊開始按鈕,人員的顏色開始變化,當(dāng)停止的時(shí)候,會(huì)有一個(gè)顏色不同的位置,那么這個(gè)位置就是被點(diǎn)到的同學(xué)了2014-05-05JS for循環(huán)中i++ 和 ++i的區(qū)別介紹
這篇文章主要介紹了JS for循環(huán)中i++ 和 ++i的區(qū)別介紹的相關(guān)資料,需要的朋友可以參考下2016-07-07js獲取或設(shè)置當(dāng)前窗口url參數(shù)的小例子
這篇文章介紹了js獲取或設(shè)置當(dāng)前窗口url參數(shù)的小例子,有需要的朋友可以參考一下2013-10-10JavaScript中in和hasOwnProperty區(qū)別詳解
in操作符只要通過(guò)對(duì)象能訪問(wèn)到屬性就返回true。hasOwnProperty()只在屬性存在于實(shí)例中時(shí)才返回true。下面通過(guò)本文給大家分享JavaScript中in和hasOwnProperty區(qū)別詳解,感興趣的朋友一起看看吧2017-08-08