CommonJS 是一个很大的规范 Node 和浏览器只是借用了它的一部分精华
先来Node环境运行的结果:
# a.jsconsole.log('我是a.js')
无引用的情况:
# b.jsconst lib = require('./a')
console.log('我是b.js')# 运行b.js我是a.js
我是b.js
有引用的情况:
# b.jsconst lib = require('./a')
console.log('我是b.js',lib)# 运行b.js我是a.js
我是b.js {} //得到一个空对象
有 exports
情况,通过 exports 定义模块的输出:
# a.jsexports.hello='world!' // 这里可以挂载合法的数据类型,对象、字符串、函数等
console.log('我是a.js')
# b.jsconst lib = require('./a')
console.log('我是b.js',lib)# 运行b.js我是a.js
我是b.js { hello: 'world!' } //得到一个含有 key 的对象 `key` 就是挂载到 `exports` 上的属性名
b.js require 的引用和 a.js exports 的引用是不是同一个引用?
# a.jsexports.hello='world!'
console.log('我是a.js')
setTimeout(()=>{console.log(exports)
},1000)
# b.jsconst lib = require('./a')
console.log('我是b.js',lib)
lib.addNewProperty = '我是b.js中新增加的属性'# 运行b.js我是a.js
我是b.js { hello: 'world!' }# 一秒后输出 说明 exports 导出的引用和 require 得到的引用是同一个引用
{ hello: 'world!', addNewProperty: '我是b.js中新增加的属性' }
如果直接导出一个函数该怎么办? exports.function?
a.jsexports.hello='world!'console.log('我是a.js')module.exports = function test(){console.log('我是a.js导出的function')
}
b.jsconst lib = require('./a')
console.log('我是b.js',lib)
lib.addNewProperty = '我是b.js中新增加的属性'
console.log(lib.hello)
console.log(lib)# 运行b.js我是a.js
我是b.js function test(){console.log('我是a.js导出的function')
}
undefined // 拿不到 exports 的引用 // addNewProperty 挂载到了 module.exports 上
{ [Function: test] addNewProperty: '我是b.js中新增加的属性' } // module.exports 会覆盖 exports 的内容
Node 中 ES6 模块和 CommonJS 采用各自的加载方案。
CommonJS
模块的输出都定义在 module.exports
这个属性上面。Node
的 import
命令加载 CommonJS
模块,Node
会自动将module.exports
属性当作模块的默认输出,即等同于 export default xxx
前端可以借助 Webpack
利用 CommonJS
的规范书写代码,Webpack
会把所有的 CommonJS
分析一遍然后生成一个大的 js
,所有的文件成为一个对象{./index.js:(function(modeule,exports,__webpack_require__){文件内容}}),./xxx.js:(function(modeule,exports){文件内容}})
通过这种形式为每个文件创建了一个作用域。
- CommonJS
// a.js module.exports = {foo: 'hello',bar: 'world' };// 等同于 export default {foo: 'hello',bar: 'world' };
总结
- 改变
require
的对象原对象也会受影响(值引用) exports
的require
的js
默认的是一个空对象,对象里面可以有函数exports
通过exports.xx
导出对象,所有的导出都挂载exports
这个对象上,require
输入默认的是一个空对象,通过这种方式定义一个对象的输出modules.exports
可以直接导出一个函数exports
和module.exports
同时存在时只会导出module.exports
的内容,会覆盖exports
import
输出的是值得引用(复制一份地址)