前言
前端本没有模块化,但是随着前端工程的发展,各个文件间的关系越来越多,为了能彼此方便地引用,慢慢地便有了模块化,这里的一个文件可以理解为一个模块。
打包就是为了让前端工程化,分离代码间的作用域。导出就是将本模块对外暴露,导入就是引入其他模块来使用其方法等。
CommonJS把每个文件当做一个独立的模块(所以这里模块和文件的概念共通),个人认为说到底就是在维护模块中的module的属性,其中有2个关键属性:第一个是exports(默认值是空的),第二个是loaded(默认值是false)。
下面通过3点来介绍如何通过这两个属性实现导入导出的控制。
补充知识点:module长啥样?
执行如下命令node ./test.js
获得如下输出:
Module { id: '.', exports: {}, // 未导出属性,所以为空 parent: null, // 如果是其他模块引用当前模块,那么引用当前模块的模块名会成为这里的parent,但是这里是直接打印当前模块module的,所以为null filename: 'D:\\project\\study-webpack\\src\\test.js', loaded: false, // 还没有被使用require调用,为false children: [], // 道理同parent,有引用其他模块时这里会显示 paths: [ 'D:\\project\\study-webpack\\src\\node_modules', 'D:\\project\\study-webpack\\node_modules', 'D:\\project\\node_modules', 'D:\\node_modules' ] }
1. CommonJS的导出
有2种写法均可以实现对模块属性的导出,以下两种均可,但是不能混用!
// 第一种写法
exports.name = 'sam';
// 第二种写法
module.exports = {
name : 'sam'
}
补充知识点:为什么不能将2种方式混用 ?
同一文件下混用会将这两个exports分别指向两个不同的对象,我们来测试下:// 创建一个test.js文件,使用nonde环境执行它,node ./test.js console.log(module.exports) // {} console.log(exports) // {} // 将两种导出进行混用 exports.name = 'sam'; module.exports = { sex : 'man' } console.log(module.exports) // { sex : 'man' } console.log(exports) // { name : 'sam' } console.log(module.exports === exports) // false
很明显生成不同的2个对象,而且无论哪个导出在前,而最终都是以
modlue.exports
为准。
2. CommonJS的导入
导入很简单,使用require
实现,而且可以通过构造表达式来导入(这将与下一篇文章中的ES6 Module导入区别,那个只能提前声明好)
// ./person.js
console.log('this is sam!')
exports.name = 'sam';
// ./info.js
let path = './person' + '.js';
let person = require(path);
console.log(person.name);
console.log('=====================');
let person2 = require('./person.js');
获得如下输出
this is sam!
sam
=====================
sam
补充知识点:为什么‘this is sam!’只输出一次?
因为第一次require时,loaded值为false,所以执行文件中的代码,第二次require时,loaded为true,表示已经加载过了,所以不再执行代码。
所以有时候我们第一次使用模块,且只需要模块中代码执行的结果,而不需要调用其他属性时,可以像这样操作:require('./test.js')
3. 小结
- CommonJS有2种导入方式,
module.exports
和exports.xxx
,且二者不能同时混用 - 第一次require导入模块时,会执行模块中的代码
内容均为我个人阅读《Webpack实战:入门、进阶与调优》后的回忆总结,这是一本很不错的书,想深入了解webpack的同学可以去看看这本书
网友评论