前言

前端模块化是一个有年代的知识,每次笔试面试遇到答的不是很好,现在整理一下相关知识,进行知识梳理,如若有帮助到您,请一键三连,当然,本文表述有问题的地方,欢迎读者指正,谢谢~

CommonJS

CommonJS 出现就是解决原本 js 文件引入出现的不足点,即 模块依赖全局污染 问题。它并不是一个 JS语言啥的,而是对于模块化的一个规范。

  • CommonJS 实际上就是用了 require 这个玩意,只要引用,就会创建一个模块的实例,即实例化(每当引入一个文件,就会将这个文件变为一个 JS 实例)

  • 做法是通过 require 引入模块,通过 module.exports 导出,并且文件加载是同步完成的。

  • 对服务端比较友好,内含缓存机制,也就是说只要 require 一个模块,那么这个模块就会被缓存,并且还会进行一次比较异同的操作,例如我修改了这个模块,那么就会将缓存的模块替换新的模块

  • 在 node 上运行,不依赖于客户端。

而当我们引入一个模块后,其实会解析成一个立即执行函数,类似于原本 ES5 利用自执行函数封装一样,类似下面,因此,引入的模块并不是全局变量

(function(exports, require, module, __filename,__dirname){

})();

AMD出现

你可能会说 AMD YES! 但次 AMD 非 AMD(正所谓此中有真意喵~)

从上文我们知道了 CommonJS 只能在 nodejs 服务端那边使用,在客户端没法运行,而 CommonJS 使用挺不错的,于是整出了这个 AMD,全称(Asynchronous Module Definition)异步模块定义,是通过 RequireJS 来实现的,区别于 CommonJS,它是异步的。

定义模块: define(moduleName, [module], factory);

引入模块:require([module], callback);

下面看这个例子:

定义一个模块 moduleA


再来定义一个模块 moduleB,此时它依赖于模块A,按照如下方式进行依赖。

然后再 index.js 文件中我们需要通过 require.config 来配置我们的模块路径,如若没有配置的话,就会报错找不到。

注意点! 上述依赖模块只有当全部加载完毕之后,才会执行后边的回调函数。这种方式就是我们比较疑惑的一个名词:前置依赖

因此,它不用考虑模块的引入顺序,并且保证是规范化的输入输出,同时,它会动态的创建 script 标签,如下图所示,它使用了 async来进行异步加载。

引出CMD

此刻,阿里也为模块化做了贡献,推出了 CMD,全称(Commin Module Definition)通用模块定义,同理,它也没办法在浏览器端运行,参考了 AMD通过 RequireJS 实现,CMD引入了 sea.js

定义模块: define(function (require, exports, module) {});

引入模块:sea.js([module路径], function(moduleA, moduleB, moduleC) {});

下面看这个例子:

定义一个模块 moduleA

再来定义一个模块 moduleB,此时它依赖于模块A,按照如下方式进行依赖。

然后再 index.js 文件中,我们需要首先通过数组确定模块路径,如下所示:

seajs.use(['module_a.js', 'module_b.js'], function(moduleA, moduleB){
console.log(moduleA.a);
console.log(moduleB.b);
})

下面总结一下 CMD 相关知识:

通过 require 加载, define 定义, exports 导出(使用 return 同理),module操作模块。

而在使用模块时,需要配置相关 url,依赖加载完毕之后,再执行回调函数,这里和 AMD 没啥区别。

注意点! 但是下面就有本质上不同了,CMD 就近依赖按需加载,增强灵活性。

ES6模块化登场

导入模块: import module from '模块路径';

导出模块:export module ;

下面看这个例子:

定义一个模块 moduleA

再来定义一个模块 moduleB,此时它依赖于模块A,按照如下方式进行依赖。

然后在 index.js 文件中我们需要配置我们的模块路径,如若没有配置的话,就会报错找不到。

ES6 模块化 与 CommonJS 对比:

先做一个实验,假设

export.js 中我们导出一个变量 a,并且进行了自加操作:

common.js 文件中,我们写入如下代码:

es6.js 文件中,我们写入如下代码:

最终结果如下:

通过例子,我们来总结一下:

区别1:

  • common.js 模块输出的是一个值的拷贝
  • ES6 模块输出的是一个值得引用

区别2:

  • common.js 运行在服务端,因此模块是在运行时加载,即程序执行时 require 才会加载。
  • ES6 模块在编译时加载

本文参考

【前端面试必备】JavaScript模块化全面解析

感谢小野老师的对JavaScript模块化的细致讲解,给老师打call,建议大家可以结合视频看一看,看完会恍然大悟的!

最后

文章产出不易,还望各位小伙伴们支持一波!

往期精选:

小狮子前端の笔记仓库

leetcode-javascript:LeetCode 力扣的 JavaScript 解题仓库,前端刷题路线(思维导图)

小伙伴们可以在Issues中提交自己的解题代码,🤝 欢迎Contributing,可打卡刷题,Give a ⭐️ if this project helped you!

访问超逸の博客,方便小伙伴阅读玩耍~

学如逆水行舟,不进则退