CommonJS规范
1 CommonJS规范
CommonJS规范中,每个文件都可以当做一个模块,并且模块的加载是同步阻塞的,也是缓存的
在服务器端,NodeJS本身实现了CommonJS
在浏览器端,在使用Browserify编译之后可以支持CmmonJS
1.2 服务器端
Node环境中,一般使用module.exports或exports, 将要暴露的变量设置成module.exports的属性
2.1.1 暴露模块
// case1
module.exports = {
fn:()=>console.log('m1 fn') // output:{ fn: [Function: fn] }
}
// case2
exports.fn = ()=>console.log('m1 fn') // output:{ fn: [Function: fn] }
// case3
exports = {
fn:()=>console.log('m1 fn') // output:{ }
}
case1和case2实际上没什么区别,因为模块暴露本质上暴露的是module对象中的exports属性。
对于case3,exports可以看做是module.exports的引用,一旦改变了exports的引用,使得exports变量不再指向module.exports,那么exports也就和module对象无关了,也就是说与模块暴露的内容无关了
Module对象:
Module {
id: 'C:\\Users\\module\\m1.js',
path: 'C:\\Users\\module',
// 模块暴露的内容
exports: {},
parent: Module {
id: '.',
path: 'C:\\Users',
exports: {},
parent: null,
filename: 'C:\\Users\\app.js',
loaded: false,
children: [ [Circular] ],
paths: []
},
filename: 'C:\\Users\\module\\m1.js',
loaded: false,
children: [],
paths: []
children: [],
paths: []
}
2.2.2 引入模块
Node环境中,一般使用require引入模块,模块在运行时加载,并且具有缓存特性,即在一个文件中多次引入同一模块,模块中的代码不会重复执行,而是直接从内存中读取模块暴露的内容
// m1
console.log('m1 loading')
exports.fn = () => console.log('m1 fn')
// m2
console.log('m2 loading')
exports.fn = () => console.log('m2 fn')
// 引入
let module1 = require('./module/m1')
let module2 = require('./module/m2')
module1.fn()
module2.fn()
/*
output:
m1 loading
m2 loading
m1 fn
m2 fn
*/
重复引入m2,由于存在缓存的原因只输出一次m2 loading
let module1 = require('./module/m1')
let module2 = require('./module/m2')
module1.fn()
module2.fn()
let _module2 = require('./module/m2')
JSON.stringify(_module2)
/*
output:
m1 loading
m2 loading
m1 fn
m2 fn
*/
1.3 浏览器端
浏览器引擎不能识别require,因此可以使用script引入browserify编译之后的文件来执行
安装:
npm install browserify -g
编译并输出:
browserify js/src/app.js -o js/dist/bundle.js
使用:
<script type="text/javascript" src="js/dist/bundle.js"></script>
1.4 总结
- 模块运行时执行,并且存在缓存,多次导入不重复执行模块代码。 ESM是模块加载时执行
- exports只是module.exports的一个引用
- 浏览器端不支持require语法,可以结合browserify编译之后使用
- 导出的是模块的拷贝