什么是模块化
事实上模块化开发最终的目的是将程序划分成一个个小的结构;
这个结构中编写属于自己的逻辑代码,有自己的作用域,不会影响到其他的结构;
这个结构可以将自己希望暴露的变量、函数、对象等导出给其结构使用;
也可以通过某种方式,导入另外结构中的变量、函数、对象等
上面说提到的结构,就是模块;按照这种结构划分开发程序的过程,就是模块化开发的过程;
没有模块化带来的问题
命名冲突问题
可以用立即执行函数解决,函数有作用域 (function{})() 匿名函数
新的问题:代码较混乱,每个文件里面都要有匿名函数,要记住每个模块返回的对象的命名
所以,模块化已经是JavaScript一个非常迫切的需求:
但是JavaScript本身,直到ES6(2015)才推出了自己的模块化方案;
在此之前,为了让JavaScript支持模块化,涌现出了很多不同的模块化规范:AMD、CMD、CommonJS等
commonjs和node
Node中对CommonJS进行了支持和实现,让我们在开发node的过程中可以方便的进行模块化开发:
在Node中每一个js文件都是一个单独的模块;
这个模块中包括CommonJS规范的核心变量:exports、module.exports、require
exports和module.exports可以负责对模块中的内容进行导出;
require函数可以帮助我们导入其他模块(自定义模块、系统模块、第三方库模块)中的内容
commonjs中的exports
导出的是exports,exports是一个空对象
导出就是往exports里加属性
commonjs中require()
require()是用来导入的,require()是一个函数,返回的是一个对象
exports导出和require()导入是同一个对象
是一个浅拷贝,引用赋值
module.exports又是什么的?
module.exports和exports有什么关系或者区别呢?
CommonJS中是没有module.exports的概念的;
但是为了实现模块的导出,Node中使用的是Module的类,每一个模块都是Module的一个实例,也就是module;
所以在Node中真正用于导出的其实根本不是exports,而是module.exports;
因为module才是导出的真正实现者;
但是,为什么感觉exports也可以导出呢?
这是因为module对象的exports属性是exports对象的一个引用;
开局module.exports=exports指向同一个对象
也就是说 module.exports = exports = main中的bar;
当用module.exports导出,不在引用exports
当我们用module.exports导出时,相当于给module.exports创建了新的对象,导出的是新对象
就没有exports的事了,不带它玩了
模块的加载过程
结论一:模块在被第一次引入时,模块中的js代码会被运行一次
结论二:模块被多次引入时,会缓存,最终只加载(运行)一次
这是因为每个模块对象module都有一个属性:loaded。
为false表示还没有加载,为true表示已经加载
结论三:如果有循环引入,那么加载顺序是什么?
Node采用的是深度优先算法
CommonJS规范缺点
CommonJS加载模块是同步的:
同步的意味着只有等到对应的模块加载完毕,当前模块中的内容才能被运行;
这个在服务器不会有什么问题,因为服务器加载的js文件都是本地文件,加载速度非常快;
应用于浏览器,浏览器加载js文件需要先从服务器将文件下载下来,之后在加载运行;
那么采用同步的就意味着后续的js代码都无法正常运行,即使是一些简单的DOM操作;
所以在浏览器中,我们通常不使用CommonJS规范:
当然在webpack中使用CommonJS是另外一回事;
因为它会将我们的代码转成浏览器可以直接执行的代码