赞
踩
今天我们来深度分析一下 Commonjs
和 Es Module
,希望通过本文的学习,能够让大家彻底明白 Commonjs
和 Es Module
原理,能够一次性搞定面试中遇到的大部分有关 Commonjs
和 Es Module
的问题。
带上疑问开始今天的分析:
exports
,为何又出了 module.exports
? 既生瑜,何生亮 ?require
模块查找机制 ?exports = {}
这种写法为何无效 ?import()
的动态引入 ?早期 JavaScript 开发很容易存在全局污染和依赖管理混乱问题。这些问题在多人开发前端应用的情况下变得更加棘手。我这里例举一个很常见的场景:
js复制代码<body>
<script src="./index.js"></script>
<script src="./home.js"></script>
<script src="./list.js"></script>
</body>
如上在没有模块化的前提下,如果在 html
中这么写,那么就会暴露一系列问题。
没有模块化,那么 script
内部的变量是可以相互污染的。比如有一种场景,如上 ./index.js
文件和 ./list.js
文件为小 A 开发的,./home.js
为小 B 开发的。
小 A 在 index.js
中声明 name 属性是一个字符串。
js
复制代码var name = '我不是外星人'
然后小 A 在 list.js
中,引用 name 属性,
js
复制代码console.log(name)
打印却发现 name 竟然变成了一个函数。刚开始小 A 不知所措,后来发现在小 B 开发的 home.js
文件中这么写道:
js复制代码function name(){
//...
}
而且这个 name 方法被引用了多次,导致一系列的连锁反应。
上述例子就是没有使用模块化开发,造成的全局污染的问题,每个加载的 js 文件都共享变量。当然在实际的项目开发中,可以使用匿名函数自执行的方式,形成独立的块级作用域解决这个问题。
只需要在 home.js 中这么写道:
js复制代码(function (){
function name(){
//...
}
})()
这样小 A 就能正常在 list.js
中获取 name 属性。但是这只是一个 demo
,我们不能保证在实际开发中情况会更加复杂。所以不使用模块开发会暴露出很多风险。
依赖管理也是一个难以处理的问题。还是如上的例子,正常情况下,执行 js 的先后顺序就是 script 标签排列的前后顺序。那么如何三个 js 之间有依赖关系,那么应该如何处理呢?
假设三个 js 中,都有一个公共方法 fun1
, fun2
, fun3
。三者之间的依赖关系如下图所示。
所以就需要模块化来解决上述的问题,今天我们就重点讲解一下前端模块化的两个重要方案:Commonjs 和 Es Module
Commonjs
的提出,弥补 Javascript 对于模块化,没有统一标准的缺陷。nodejs 借鉴了 Commonjs
的 Module ,实现了良好的模块化管理。
目前 commonjs
广泛应用于以下几个场景:
Node
是 CommonJS 在服务器端一个具有代表性的实现;Browserify
是 CommonJS 在浏览器中的一种实现;webpack
打包工具对 CommonJS 的支持和转换;也就是前端应用也可以在编译之前,尽情使用 CommonJS 进行开发。在使用 规范下,有几个显著的特点。
commonjs
中每一个 js 文件都是一个单独的模块,我们可以称之为 module;导出:我们先尝试这导出一个模块:
hello.js
中
js复制代码let name = '《React进阶实践指南》'
module.exports = function sayName (){
return name
}
导入:接下来简单的导入:
home.js
js复制代码const sayName = require('./hello.js')
module.exports = function say(){
return {
name:sayName(),
author:'我不是外星人'
}
}
如上就是 Commonjs 最简单的实现,那么暴露出两个问题:
首先从上述得知每个模块文件上存在 module
,exports
,require
三个变量,然而这三个变量是没有被定义的,但是我们可以在 Commonjs 规范下每一个 js 模块上直接使用它们。在 nodejs 中还存在 __filename
和 __dirname
变量。
如上每一个变量代表什么意思呢:
module
记录当前模块信息。require
引入模块的方法。exports
当前模块导出的属性在编译的过程中,实际 Commonjs 对 js 的代码块进行了首尾包装, 我们以上述的 home.js 为例子
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。