// CommonJS模塊引入模塊
let { stat, exists, readFile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
readfile = _fs.readfile;
這種加載稱為“運(yùn)行時加載”曙旭,因?yàn)橹挥羞\(yùn)行時才能得到這個對象,導(dǎo)致完全沒辦法在編譯時做“靜態(tài)優(yōu)化”。
ES6 模塊不是對象,而是通過export命令顯式指定輸出的代碼萄焦,再通過import命令輸入楷扬。
// ES6模塊
import { stat, exists, readFile } from 'fs';
面代碼的實(shí)質(zhì)是從fs模塊加載3個方法,其他方法不加載。這種加載稱為“編譯時加載”或者靜態(tài)加載,即 ES6 可以在編譯時就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。當(dāng)然,這也導(dǎo)致了沒法引用 ES6 模塊本身,因?yàn)樗皇菍ο蟆?/h5>
多的不多說就說一些基本用法個人粗劣的大白話
improt 就是簡單的引入模塊配合export使用 export是暴露
建一個文件
// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
通過export來暴露變量方法 也可以使用export{}
如果不用{} 但是不能直接使用實(shí)際的常量值
引用加載
// main.js
import { area, circumference } from './circle';
console.log('圓面積:' + area(4));
console.log('圓周長:' + circumference(14));
使用import{}form+"路徑"來引用
加載所有暴露的變量方法
import * as circle from './circle';
console.log('圓面積:' + circle.area(4));
console.log('圓周長:' + circle.circumference(14));
*代表所有 as 可以自定義一個變量名字
exprot default
從前面的例子可以看出噩咪,使用import命令的時候仆百,用戶需要知道所要加載的變量名或函數(shù)名,否則無法加載。但是,用戶肯定希望快速上手拴曲,未必愿意閱讀文檔蕉汪,去了解模塊有哪些屬性和方法
export default為模塊指定默認(rèn)輸出驹马。
// export-default.js
export default function () {
console.log('foo');
}
上面代碼是一個模塊文件export-default.js泳姐,它的默認(rèn)輸出是一個函數(shù)阎肝。
其他模塊加載該模塊時眼刃,import命令可以為該匿名函數(shù)指定任意名字。
// import-default.js
import customName from './export-default';
customName(); // 'foo'
export default命令用在非匿名函數(shù)前赴恨,也是可以的额港。
// export-default.js
export default function foo() {
console.log('foo');
}
// 或者寫成
function foo() {
console.log('foo');
}
export default foo;
上面代碼中向瓷,foo函數(shù)的函數(shù)名foo,在模塊外部是無效的。加載的時候,視同匿名函數(shù)加載巢钓。
下面比較一下默認(rèn)輸出和正常輸出咬展。
// 第一組
export default function crc32() { // 輸出
// ...
}
import crc32 from 'crc32'; // 輸入
// 第二組
export function crc32() { // 輸出
// ...
};
import {crc32} from 'crc32'; // 輸入
本質(zhì)上玖媚,export default就是輸出一個叫做default的變量或方法淹真,然后系統(tǒng)允許你為它取任意名字陷寝。所以,下面的寫法是有效的。只不過省略了default而已
// modules.js
function add(x, y) {
return x * y;
}
export {add as default};//輸出default
// 等同于
// export default add;
// app.js
import { default as xxx } from 'modules';
// 等同于
// import xxx from 'modules';
輸出所有
export * from 'circle';
輸出暴露 'circle';的所有屬性方法
引入所有的
import * as math from 'circleplus';
引入 'circleplus'';的所有屬性方法
跨模塊常量
一個值要被多個模塊共享
// constants.js 模塊
export const A = 1;export const B = 3;export const C = 4;
//test1.js 模塊
import * as constants from './constants';console.log(constants.A);
// 1console.log(constants.B); // 3
// test2.js 模塊
import {A, B} from './constants';console.log(A); // 1console.log(B); // 3
如果要使用的常量非常多彻犁,可以建一個專門的constants
目錄森篷,將各種常量寫在不同的文件里面,保存在該目錄下抖韩。
// constants/db.js
export const db = {
url: 'http://my.couchdbserver.local:5984',
admin_username: 'admin',
admin_password: 'admin password
'};
// constants/user.js
export const users = ['root', 'admin', 'staff', 'ceo', 'chief', 'moderator'];
然后席揽,將這些文件輸出的常量熊痴,合并在index.js里面许赃。
// constants/index.js
export {db} from './db';export {users} from './users';
使用的時候沟于,直接加載index.js就可以了。
// script.js
import {db, users} from './constants';
inmprot()方法
inport命令會被 JavaScript 引擎靜態(tài)分析供搀,先于模塊內(nèi)的其他模塊執(zhí)行(叫做”連接“更合適)摄悯。所以撒遣,下面的代碼會報錯义黎。
// 報錯
if (x === 2) {
import MyModual from './myModual';
}
引擎處理import語句是在編譯時 import和export命令只能在模塊的頂層,不能在代碼塊之中(比如层释,在if代碼塊之中贡羔,或在函數(shù)之中)。
如果import命令要取代 Node 的require方法弄息,這就形成了一個障礙缨称。因?yàn)閞equire是運(yùn)行時加載模塊权纤,import命令無法取代require的動態(tài)加載功能妖碉。
const path = './' + fileName;
const myModual = require(path);
上面的語句就是動態(tài)加載,require到底加載哪一個模塊芥被,只有運(yùn)行時才知道欧宜。import語句做不到這一點(diǎn)。
因此拴魄,有一個提案冗茸,建議引入import()函數(shù),完成動態(tài)加載匹中。
import(specifier)
上面代碼中夏漱,import函數(shù)的參數(shù)specifier,指定所要加載的模塊的位置顶捷。import命令能夠接受什么參數(shù)挂绰,import()函數(shù)就能接受什么參數(shù),兩者區(qū)別主要是后者為動態(tài)加載服赎。import() 返回一個 Promise 對象葵蒂。
js的異步加載
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
es6
<script src="...js" type="module"></script>
自動異步 也可以設(shè)置async同步
——————————
ES6 模塊與 CommonJS 模塊的差異
討論 Node 加載 ES6 模塊之前,必須了解 ES6 模塊與 CommonJS 模塊完全不同重虑。
它們有兩個重大差異践付。
CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用缺厉。
CommonJS 模塊是運(yùn)行時加載永高,ES6 模塊是編譯時輸出接口。
第二個差異是因?yàn)?CommonJS 加載的是一個對象(即module.exports屬性)提针,該對象只有在腳本運(yùn)行完才會生成命爬。而 ES6 模塊不是對象,它的對外接口只是一種靜態(tài)定義辐脖,在代碼靜態(tài)解析階段就會生成遇骑。
CommonJS 模塊輸出的是值的拷貝,也就是說揖曾,一旦輸出一個值落萎,模塊內(nèi)部的變化就影響不到這個值
ES6模塊的轉(zhuǎn)碼
瀏覽器目前還不支持ES6模塊亥啦,為了現(xiàn)在就能使用,可以將轉(zhuǎn)為ES5的寫法练链。除了Babel可以用來轉(zhuǎn)碼之外翔脱,還有以下兩個方法,也可以用來轉(zhuǎn)碼媒鼓。
1:ES6 module transpiler
ES6 module transpiler是 square 公司開源的一個轉(zhuǎn)碼器届吁,可以將 ES6 模塊轉(zhuǎn)為 CommonJS 模塊或 AMD 模塊的寫法,從而在瀏覽器中使用绿鸣。
首先疚沐,安裝這個轉(zhuǎn)碼器。
$ npm install -g es6-module-transpiler
然后潮模,使用compile-modules convert 命令亮蛔,將 ES6 模塊文件轉(zhuǎn)碼。
$ compile-modules convert file1.js file2.js
參數(shù)可以指定轉(zhuǎn)碼后的文件名擎厢。
$ compile-modules convert -o out.js file1.js
————————————————————————————
SystemJS
另一種解決方法是使用 SystemJS究流。它是一個墊片庫(polyfill),
可以在瀏覽器內(nèi)加載 ES6 模塊动遭、AMD 模塊和 CommonJS 模塊芬探,
將其轉(zhuǎn)為 ES5 格式。它在后臺調(diào)用的是 Google 的 Traceur 轉(zhuǎn)碼器厘惦。
--
使用時偷仿,
先在網(wǎng)頁內(nèi)載入system.js文件。
<script src="system.js"></script>
然后宵蕉,使用System.import方法加載模塊文件酝静。
<script> System.import('./app.js');</script>
--
上面代碼中的./app
,指的是當(dāng)前目錄下的app.js文件国裳。它可以是ES6模塊文件形入,System.import
會自動將其轉(zhuǎn)碼
----全跨。
需要注意的是缝左,System.import使用異步加載,返回一個 Promise 對象浓若,可以針對這個對象編程渺杉。下面是一個模塊文件。
// app/es6-file.js:export class q { constructor() { this.es6 = 'hello'; }}
然后挪钓,在網(wǎng)頁內(nèi)加載這個模塊文件是越。
<script>System.import('app/es6-file').then(function(m) { console.log(new m.q().es6); // hello});</script>
--
上面代碼中,System.import
方法返回的是一個 Promise 對象碌上,所以可以用then
方法指定回調(diào)函數(shù)倚评。