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

前言:本文着重介绍ES5和ES6的模块化加载,至于AMD和CMD因为已经过时了,仅仅只是提了下。早些年的前端都仅仅只是静态页面,还没有模块化这个概念,但随着时间的推移,前端代码愈发庞大,那么自然而然会暴露很多问题:

  • 命名冲突
  • 文件依赖

那个时候都是通过匿名自执行函数来解决命名冲突,文件依赖只能手动保证引入的顺序正确,直到后来某国外大神造出来Require.js,从此前端模块化的概念就出现了;再后来淘宝前端大神玉伯根据require.js的思想造出了sas.js,至此,两大模块加载器在前端领域独领风骚一段时间。

1. AMD

AMDRequireJS 在推广过程中对模块定义的规范化产出,是浏览器端的模块化解决方案。

2. CMD

CMD是 SeaJS 在推广过程中对模块定义的规范化产出,是浏览器端的模块化解决方案。

3. AMD与CMD的差异

  • AMD是提前执行(RequireJS2.0开始支持延迟执行,不过只是支持写法,实际上还是会提前执行),CMD是延迟执行
  • AMD推荐依赖前置,CMD推荐依赖就近

4. CommonJS

CommonJS是NodeJs服务器端模块的规范,ES Module是在ES5中推出的,基于CommonJS规范,而export和export default是ES6中的模块化加载语法。
在这之前,必须了解 ES6 模块与 CommonJS 模块完全不同。它们有两个重大差异:

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。具体可参考阮一峰大神的ES6文章Module加载语法

重点来了,下面着重介绍ES5中和ES6中的模块化加载方案:

ES5中exports和module.exports的区别

module.exports才是真正的接口,exports只不过是它的一个辅助工具。nodejs只会导出module.exports的指向,最终返回给调用者的是module.exports而不是exports。
所有的exports收集到的属性和方法,都赋值给了Module.exports。当然,这有个前提,就是module.exports本身不具备任何属性和方法。
如果,module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。

挂载在exports上的方式和属性,都会传递给module.exports。二者没区别。

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,那就说明module.exports和exports的引用关系断开了,二者不相等了。

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开发者注意一下两点:

  1. 最好别分别定义module.exports和exports
  2. 导出对象用module.exports,导出多个方法和变量用exports

导出多个属性或方法:

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

导出一个对象:

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,因为nodejs只会导出module.exports的指向

ES6中export 和 export default区别

  1. export与export default均可用于导出常量、函数、文件、模块等
  2. 在一个文件或模块中,export、import可以有多个,export default仅有一个
  3. export方式只能具名导入,在导入时要加{ };export default则只能匿名导入
  4. export能直接导出变量表达式,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引入时必须具名导入,也就是需要声明式指定对象里的key来导入你需要的

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也支持具名导入
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 // 报错:export default只能用一次
console.log(module.exports) // { default: { name: 'UncleFirefly', age: 25 } }

只能匿名导入

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

如果使用require引入的话,必须通过default属性拿到实际导出的变量:

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

export与import混合使用

具名接口改为默认接口的写法如下:

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

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

同样地,默认接口也可以改名为具名接口:

export { default as es6 } from './someModule';
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342