为什么需要模块化?
假如没有模块化,在前端开发时可能存在下面的问题:
- 变量和方法不容易维护,容易污染到全局作用域。
- 通过script标签进行大量引入资源,代码可读性和可维护性都比较差。
- 代码一多就比较复杂。
- 多人合作的场景下,资源的引入会带来比较大的困难。
JS模块化的演变史
1. CommonJS
我们熟知的Node.js在模块化方面就是遵守的CommonJS规范。CommonJS模块化具有下面几个特点:
- 模块内的代码运行在模拟作用域中,不会污染到全局作用域中。
- 模块可以多次引入,但只会在第一次加载的时候执行一次,后面的运行都是从缓存中获取值。
- 代码出现的顺序就是模块加载的顺序。
模块的导入导出方式:
通过module.exports或者exports进行导出,通过require进行导入。
module.exports = {age: 1,name: 'hello'}
const foo = require('./foo.js');
2. ES6 Module
CommonJS不适合浏览器等场景,于是ES6 Module诞生了,它是ES6之后新增的模块化规范。
模块的导入导出方式:
通过export导出模块,通过import导入模块。在导出的时候有两种方式,一种是默认暴露,一种是分别暴露。
问题汇总
RQ1:浏览器为什么不适用CommonJS?
因为CommonJS的require语法是同步的,在浏览器端文件一般存放在服务器上,一般通过网络请求来获取数据,如果使用CommonJS会导致时间很长,造成浏览器卡顿现象,NodeJS之所以采用CommonJS是因为NodeJS在服务端读取的是本地硬盘,因此速度比较快。
RQ2:CommonJS和ES6 Module之间的区别
- CommonJS输出的是值的拷贝,而ES6 Module输出的是值的引用。
- CommonJS模块是运行时加载,ES6 Moduke是编译时输出接口。
- CommonJS加载是同步的可能阻塞的,ES6 Module是异步加载。
RQ3:在Node.js中module.exports和exports有什么区别?
- 通过module.exports暴露的函数,在引入的时候可以不知道函数名,但是通过exports暴露的内容必须知道名字。
- exports对象是module对象的一个属性,初始时module.exports和exports指向的是同一块内存区域。
- 模块导出的是module.exports,exports只是和它指向的是同一片内存,在不改变exports内存的情况下,修改exports的值可以改变module.exports的值。
- 导出时尽量使用module.exports以避免赋值导致的混乱。