ES Module之exports晃财、module.exports、export和export default

前言:本文著重介紹ES5和ES6的模塊化加載典蜕,至于AMD和CMD因?yàn)橐呀?jīng)過(guò)時(shí)了断盛,僅僅只是提了下。早些年的前端都僅僅只是靜態(tài)頁(yè)面愉舔,還沒有模塊化這個(gè)概念钢猛,但隨著時(shí)間的推移,前端代碼愈發(fā)龐大轩缤,那么自然而然會(huì)暴露很多問(wèn)題:

  • 命名沖突
  • 文件依賴

那個(gè)時(shí)候都是通過(guò)匿名自執(zhí)行函數(shù)來(lái)解決命名沖突命迈,文件依賴只能手動(dòng)保證引入的順序正確,直到后來(lái)某國(guó)外大神造出來(lái)Require.js火的,從此前端模塊化的概念就出現(xiàn)了壶愤;再后來(lái)淘寶前端大神玉伯根據(jù)require.js的思想造出了sas.js,至此馏鹤,兩大模塊加載器在前端領(lǐng)域獨(dú)領(lǐng)風(fēng)騷一段時(shí)間征椒。

1. AMD

AMDRequireJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)出,是瀏覽器端的模塊化解決方案湃累。

2. CMD

CMD是 SeaJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)出勃救,是瀏覽器端的模塊化解決方案。

3. AMD與CMD的差異

  • AMD是提前執(zhí)行(RequireJS2.0開始支持延遲執(zhí)行治力,不過(guò)只是支持寫法蒙秒,實(shí)際上還是會(huì)提前執(zhí)行),CMD是延遲執(zhí)行
  • AMD推薦依賴前置宵统,CMD推薦依賴就近

4. CommonJS

CommonJS是NodeJs服務(wù)器端模塊的規(guī)范晕讲,ES Module是在ES5中推出的,基于CommonJS規(guī)范马澈,而export和export default是ES6中的模塊化加載語(yǔ)法瓢省。
在這之前,必須了解 ES6 模塊與 CommonJS 模塊完全不同箭券。它們有兩個(gè)重大差異:

  • CommonJS 模塊輸出的是一個(gè)值的拷貝,ES6 模塊輸出的是值的引用疑枯。
  • CommonJS 模塊是運(yùn)行時(shí)加載辩块,ES6 模塊是編譯時(shí)輸出接口。

第二個(gè)差異是因?yàn)?CommonJS 加載的是一個(gè)對(duì)象(即module.exports屬性),該對(duì)象只有在腳本運(yùn)行完才會(huì)生成废亭。而 ES6 模塊不是對(duì)象国章,它的對(duì)外接口只是一種靜態(tài)定義,在代碼靜態(tài)解析階段就會(huì)生成豆村。具體可參考阮一峰大神的ES6文章Module加載語(yǔ)法液兽。

重點(diǎn)來(lái)了,下面著重介紹ES5中和ES6中的模塊化加載方案:

ES5中exports和module.exports的區(qū)別

module.exports才是真正的接口掌动,exports只不過(guò)是它的一個(gè)輔助工具四啰。nodejs只會(huì)導(dǎo)出module.exports的指向,最終返回給調(diào)用者的是module.exports而不是exports粗恢。
所有的exports收集到的屬性和方法柑晒,都賦值給了Module.exports。當(dāng)然眷射,這有個(gè)前提匙赞,就是module.exports本身不具備任何屬性和方法。
如果妖碉,module.exports已經(jīng)具備一些屬性和方法涌庭,那么exports收集來(lái)的信息將被忽略。

掛載在exports上的方式和屬性欧宜,都會(huì)傳遞給module.exports坐榆。二者沒區(qū)別。

exports.fun = function() {
    console.log('Hello world')
}
exports.messgae = 'Nice to meet you'

var isEq = (exports === module.exports);
console.log(exports);
console.log(module.exports);
console.log(isEq);
// output:
// { fun: [Function], message: 'Nice to meet you' }
// { fun: [Function], message: 'Nice to meet you' }
// true

支持用importrequire的具名和匿名引入

let mod = require('./mod.js') // mod: // { fun: [Function], message: 'Nice to meet you' }
import { fun, messgae } from './mod.js' // fun: [Function], message: Nice to meet you

直接把變量賦值給exports鱼鸠,那么exports指向變了猛拴,那就僅僅是exports不再指向module.exports

exports.fun = function() {
    console.log('Hello world')
}
exports = 'Nice to meet you'

var isEq = (exports === module.exports);
console.log(exports);
console.log(module.exports);
console.log(isEq);
// output
// Nice to meet you
// { fun: [Function] }
// false

let mod = require('./mod.js') // mod: // { fun: [Function] }

直接把變量賦值給module.exports,那就說(shuō)明module.exports和exports的引用關(guān)系斷開了蚀狰,二者不相等了愉昆。

exports.fun = function() {
    console.log('Hello world')
}

module.exports = 'Nice to meet you'

var isEq = (exports === module.exports);
console.log(exports);
console.log(module.exports);
console.log(isEq);
// output:
// { fun: [Function] }
// Nice to meet you
// false

let mod = require('./exports.js') // mod: Nice to meet you

??建議NodeJS開發(fā)者注意一下兩點(diǎn):

  1. 最好別分別定義module.exports和exports
  2. 導(dǎo)出對(duì)象用module.exports,導(dǎo)出多個(gè)方法和變量用exports

導(dǎo)出多個(gè)屬性或方法:

exports.fun = function() {
    console.log('Hello world')
}

exports.message = 'Nice to meet you'

// 匿名引入
let mod = require('./mod.js') // { fun: [Function], message: 'Nice to meet you' }
// or 具名引入
let { fun, message } = require('./mod.js') // [Function], Nice to meet you

導(dǎo)出一個(gè)對(duì)象:

let fun = function() {
    console.log('Hello world')
}

let message = 'Nice to meet you'

module.exports = {
    fun,
    message
}

// 匿名引入
let mod = require('./mod.js') // { fun: [Function], message: 'Nice to meet you' }
// or 具名引入
let { fun, message } = require('./mod.js') // [Function], Nice to meet you

??這里必須用module.exports,而不能用exports麻蹋,因?yàn)閚odejs只會(huì)導(dǎo)出module.exports的指向

ES6中export 和 export default區(qū)別

  1. export與export default均可用于導(dǎo)出常量跛溉、函數(shù)、文件扮授、模塊等
  2. 在一個(gè)文件或模塊中芳室,export、import可以有多個(gè)刹勃,export default僅有一個(gè)
  3. export方式只能具名導(dǎo)入堪侯,在導(dǎo)入時(shí)要加{ };export default則只能匿名導(dǎo)入
  4. export能直接導(dǎo)出變量表達(dá)式荔仁,export default不行伍宦。

export

const Programmer = {name: 'UncleFirefly',age:25}
export let message = 'hello'
export { Programmer }
console.log(module.exports) // { message: 'hello', Programmer: { name: 'UncleFirefly', age: 25 } }

import引入時(shí)必須具名導(dǎo)入芽死,也就是需要聲明式指定對(duì)象里的key來(lái)導(dǎo)入你需要的

import { Programmer } from './mod.js' // Programmer: {name: 'UncleFirefly',age:25}

如果使用require引入的話,則可以直接匿名引入

let mod = require('./mod.js') // mod: {  message: 'hello', Programmer: { name: 'UncleFirefly', age: 25 } }

// or require也支持具名導(dǎo)入
let { Programmer } = require('./export.js') // Programmer: {name: 'UncleFirefly',age:25}

export default

const message = 'hello'
const Programmer = {name: 'UncleFirefly',age:25}
export default Programmer
// export default message // 報(bào)錯(cuò):export default只能用一次
console.log(module.exports) // { default: { name: 'UncleFirefly', age: 25 } }

只能匿名導(dǎo)入

import mod from './mod.js' // mod: { name: 'UncleFirefly', age: 25 }

如果使用require引入的話次洼,必須通過(guò)default屬性拿到實(shí)際導(dǎo)出的變量:

let mod = require('./mod.js') // mod: { default: { name: 'UncleFirefly', age: 25 } }

export與import混合使用

具名接口改為默認(rèn)接口的寫法如下:

export { es6 as default } from './someModule';

// 等同于
import { es6 } from './someModule';
export default es6;

同樣地关贵,默認(rèn)接口也可以改名為具名接口:

export { default as es6 } from './someModule';
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市卖毁,隨后出現(xiàn)的幾起案子揖曾,更是在濱河造成了極大的恐慌,老刑警劉巖亥啦,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炭剪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡禁悠,警方通過(guò)查閱死者的電腦和手機(jī)念祭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)碍侦,“玉大人粱坤,你說(shuō)我怎么就攤上這事〈刹” “怎么了站玄?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)濒旦。 經(jīng)常有香客問(wèn)我株旷,道長(zhǎng),這世上最難降的妖魔是什么尔邓? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任晾剖,我火速辦了婚禮,結(jié)果婚禮上梯嗽,老公的妹妹穿的比我還像新娘齿尽。我一直安慰自己,他們只是感情好灯节,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布循头。 她就那樣靜靜地躺著,像睡著了一般炎疆。 火紅的嫁衣襯著肌膚如雪卡骂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天形入,我揣著相機(jī)與錄音全跨,去河邊找鬼。 笑死亿遂,一個(gè)胖子當(dāng)著我的面吹牛浓若,可吹牛的內(nèi)容都是我干的盒使。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼七嫌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了苞慢?” 一聲冷哼從身側(cè)響起诵原,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挽放,沒想到半個(gè)月后绍赛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辑畦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年吗蚌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纯出。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚯妇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出暂筝,到底是詐尸還是另有隱情箩言,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布焕襟,位于F島的核電站陨收,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鸵赖。R本人自食惡果不足惜务漩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望它褪。 院中可真熱鬧饵骨,春花似錦、人聲如沸列赎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)包吝。三九已至饼煞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诗越,已是汗流浹背砖瞧。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嚷狞,地道東北人块促。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓荣堰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親竭翠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子振坚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355