持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
随着前端页面的不断壮大,页面也越来越负责,本来在最开始的时候js是没有模块化的,但是项目越来越负责,为了后期管理的容易,催生出了模块化的概念,这是一种管理规范,通过分割模块的形式解耦各个功能。
没有模块化带来的问题
早期js是没有模块化的概念的,对于js代码我们在一个文件夹中写好后在html文件中进行引入,但是这样就会带来问题,尤其是现在前端的代码量越来越大,有的时候涉及到了团队协作开发,这个时候没有模块化的概念就会出现变量重复等问题。
最开始的方案
为了解决js作用域的问题,我们一开始是使用立即执行函数来解决的,因为js没有块级作用域的概念,只有函数作用域,所以只能通过函数来模拟块级作用域,来实现作用域的分离。
(function(){...})();
这很好的解决了作用域的问题,但是对于加载的顺序问题依旧存在(对于文件的引用有加载顺序的要求)。
commonJS
我们熟悉的node就是使用的commonJS。其特点是优先从缓存中加载,其不能在浏览器端使用,其模块的加载是同步的,所以不能符合浏览器的异步环境,其中模块的引入是通过require语法,模块的导师是通过module.exports或者exports输出的值是拷贝值,需要注意这里的exports是module.exports的值的引用。
exports 和 module.exports 的区别
- 每个模块中都有一个 module 对象
- module 对象中有一个 exports 对象
- 我们可以把需要导出的成员都挂载到 module.exports 接口对象中
- 也就是:
moudle.exports.xxx = xxx的方式 - 但是每次都
moudle.exports.xxx = xxx很麻烦,点儿的太多了 - 所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:
exports exports === module.exports结果为trues- 所以对于:
moudle.exports.xxx = xxx的方式 完全可以:expots.xxx = xxx - 当一个模块需要导出单个成员的时候,这个时候必须使用:
module.exports = xxx的方式 - 不要使用
exports = xxx不管用 - 因为每个模块最终向外
return的是module.exports - 而
exports只是module.exports的一个引用 - 所以即便你为
exports = xx重新赋值,也不会影响module.exports - 但是有一种赋值方式比较特殊:
exports = module.exports这个用来重新建立引用关系的
AMD
为了能在浏览器端实现模块化,所以推出了AMD的模块化规范,其实现库有RequireJS,其支持异步加载使用如下:
-
define(moduleName, [module], factory)定义模块,一个文件可设置多个模块 -
require([module], callback)引入模块
ES module
对于熟悉脚手架开发的前端开发者来说这个规范一定不陌生,要注意前面介绍的commonJS、AMD、CMD等都不是ES官方的标准,为了实现统一的规范,于是ES6版本中官方才从语言层面实现了模块化的功能。示例如下
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
我们通过export来导出模块,可以有默认暴露export default 但是一个文件只能有一个默认暴露,同时还可以有分别暴露的形式,不同的暴露形式对应不同的导入,对于默认暴露我们直接import后接随意的名字皆可,但是对于分别暴露就要使用{对应名字}的形式来导入:
默认暴露
let a=11;
export defalut a;
import a from "a.js"
import otherName from "a.js"
分别暴露
let a=11;
export a;
import {a} from "a.js"
注意在浏览器端使用ES6模块时:
<script type="module" src="a.js"></script>