ES6與CommonJS中的模塊處理的區(qū)別
ES6和CommonJS都有自己的一套處理模塊化代碼的措施,即JS文件之間的相互引用。
為了方便兩種方式的測(cè)試,使用nodejs的環(huán)境進(jìn)行測(cè)試
CommonJS的模塊處理
使用require來(lái)引入其他模塊的代碼,使用module.exports來(lái)引出
// exportDemo.js count = 1; module.exports.count = count; module.exports.Hello = function() { var name; this.setName = function(newName) { name = newName; } this.sayHello = function() { console.log("hello Mr." + name); } this.getId = function() { return count++ } }
// requireDemo.js var {Hello} = require("./exportDemo") var hello = new Hello(); hello.setName("Blank"); hello.sayHello();
在終端執(zhí)行 node requireDemo.js
,返回結(jié)果為'hello Mr.Blank'
導(dǎo)出的Hello函數(shù)是原函數(shù)的一次拷貝,修改Hello函數(shù)的屬性值不會(huì)對(duì)其他require的地方造成影響
var { Hello, count } = require('./exportDemo') var hello = new Hello(); // 讓count自增 console.log(hello.getId()); console.log(hello.getId()); // 發(fā)現(xiàn)獲取的count還是原值 console.log(count) // 真正的count其實(shí)是已經(jīng)改了的 var newHello = new Hello(); console.log(newHello.getId()) var { Hello: newHello, count: newCount } = require('./exportDemo') console.log(newCount, 'newCount'); // 再次require,取得的newHello和之前require的Hello指向同一個(gè)拷貝 console.log(newHello === Hello)
ES6的模塊處理
nodejs中運(yùn)行ES6風(fēng)格的代碼
nodejs默認(rèn)是不支持ES6的模塊處理方案的。
但是在8.5.0之后,ES6代碼的文件格式定為mjs后,可使用 node --experimental-modules xxx.mjs
運(yùn)行。
// exportDemo.mjs export let a = 1;
// importDemo.mjs import {a} from './exportDemo.mjs' console.log(a)
與CommonJS模塊處理的區(qū)別
CommonJS 模塊輸出的是一個(gè)值的拷貝(已在上一章驗(yàn)證),ES6 模塊輸出的是值的引用。
// exportDemo.mjs export let counter = 1; export function incCounter() { counter ++; }
// importDemo.mjs import { counter, incCounter } from './exportDemo.mjs' incCounter(); console.log(counter) // 打印結(jié)果為2,而不是初始值的1
CommonJS模塊是運(yùn)行時(shí)加載,ES6模塊是編譯時(shí)輸出接口
Nodejs此類的運(yùn)行環(huán)境會(huì)在一個(gè)閉包中運(yùn)行CommonJS模塊代碼
(function(exports, require, module, __filename, __dirname) { // Module code actually lives in here });
ES6 模塊不會(huì)緩存運(yùn)行結(jié)果,而是動(dòng)態(tài)地去被加載的模塊取值,并且變量總是綁定其所在的模塊。
// exportDemo.mjs export let a = 1; export const b = 2; export let obj = {}; // importDemo.mjs import { a, b } from './exportDemo.mjs' console.log(a, b) a = 1 // 報(bào)錯(cuò),TypeError: Assignment to constant variable,export出來(lái)的值是一個(gè)只讀引用 obj.x = 1 // 可以改變屬性值
在ES6模塊中我們更多地要去考慮語(yǔ)法的問(wèn)題 export default
有時(shí)候我們會(huì)在代碼發(fā)現(xiàn) export default obj
的用法,那么這個(gè)default是用來(lái)干嘛的?
default是ES6引入的與export配套使用的關(guān)鍵字,用來(lái)給匿名對(duì)象、匿名函數(shù)設(shè)置默認(rèn)的名字用的
export出來(lái)的值必須要有一個(gè)命名,否則從語(yǔ)法層次便會(huì)報(bào)錯(cuò)
讓我們看一下以下幾個(gè)會(huì)報(bào)錯(cuò)的錯(cuò)誤例子
export匿名對(duì)象
export { x: 1 } // 報(bào)錯(cuò),SyntaxError:Unexpected token,這是一個(gè)編譯階段的錯(cuò)誤 // 正確寫法 export default { x: 1 }
export匿名函數(shù)
export function() {} // 報(bào)錯(cuò),SyntaxError: Unexpected token ( // 正確寫法 export default function() {}
循環(huán)引用(recycling loading)
在復(fù)雜的模塊中,可能會(huì)出現(xiàn)模塊間的 互相引用 。
commonJS的循環(huán)引用運(yùn)行機(jī)制
// a.js exports.loaded = false; var b = require('./b.js') console.log("b in a is " + JSON.stringify(b)) exports.loaded = true; console.log("a complete")
// b.js exports.loaded = false; var a = require('./a.js') console.log("a in b is " + JSON.stringify(a)) exports.loaded = true; console.log("b complete")
// main.js var a = require('./a.js') var b = require('./b.js') console.log("a in main is" + JSON.stringify(a)) console.log("b in main is" + JSON.stringify(b))
執(zhí)行指令 nodejs main.js
時(shí)序圖下的執(zhí)行步驟分解圖如下所示:
ES6的循環(huán)引用運(yùn)行機(jī)制
一個(gè)會(huì)報(bào)錯(cuò)的例子
// a.mjs import { bar } from './b.mjs' console.log(bar); export let foo = 'foo from a.mjs'
// b.mjs import { foo } from './a.mjs' console.log(foo) export let bar = 'bar from b.mjs'
// main.mjs import { foo } from './a.mjs' import { bar } from './b.mjs'
node main.mjs
時(shí)序圖下的執(zhí)行步驟分解圖如下所示:
ES6的循環(huán)引用要特別注意變量是否已被聲明,若未被聲明的塊級(jí)作用域變量被其他模塊引用時(shí),會(huì)報(bào)錯(cuò)。
改進(jìn)方案:循環(huán)引用中盡量去export可以提前確定的值(例如函數(shù)),其實(shí)我們總是希望去 引用模塊執(zhí)行完全后最終確定的變量 。
// a.mjs import { bar } from './b.mjs' console.log(bar()); export function foo() { return 'foo from a.mjs' }
// b.mjs import { foo } from './a.mjs' console.log(foo()); export function bar() { return 'bar from b.mjs' }
// main.mjs import { foo } from './a.mjs' import { bar } from './b.mjs'
node main.mjs
返回結(jié)果:
foo from a.mjs
bar from b.mjs
時(shí)序圖下的執(zhí)行步驟分解圖如下所示:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
一起來(lái)了解一下JavaScript的預(yù)編譯(小結(jié))
這篇文章主要介紹了一起來(lái)了解一下JavaScript的預(yù)編譯(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03微信小程序遍歷Echarts圖表實(shí)現(xiàn)多個(gè)餅圖
這篇文章主要介紹了微信小程序遍歷Echarts圖表實(shí)現(xiàn)多個(gè)餅圖,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04