1. 什么是模块
- 一个具有特定功能的文件就是一个模块
- 模块的优点: 有了模块,我们就可以非常方便地使用这些模块,因为模块总是完成了特定的功能,如果要修改模块中个功能,那么只需要修改这个自己的模块文件即可,模块独立于每一个文件中,不影响模块的代码。模块独立于每一个文件中,不影响模块的代码
- 模块之间相互独立,如果一个模块引入另一模块,要使用里面的值,我们就需要在被引入的模块中暴露这些值
2. 模块化
-
将一个复杂的程序依据一定的规则(规范)封装成几个模块(文件),并进行组合在一起,每个模块内部数据实现是私有的, 只是向外部暴露一些接口(方法)与外部其他模块进行通信
-
按照模块化思考开发的项目, 也被称为模块化开发
-
模块化的发展
① 全局开发模式
// 最早期所有的js代码写在一个js文件中 function foo(){} function bar(){} // 造成的问题,就是代码量过大以后,Global全局被污染,很容易导致命名冲突
② 命名空间
对代码进行简单的封装,减少global变量的数量
// 简单封装: Namespac 模式, 就是我们俗称的命名空间 var Namespac = { foo: function(){}, bar: function(){} } // 本质就是对象,不太安全
③ IIFE模式:是一个在定义时就会立即执行的JavaScript函数。
var Module = (function(){ var foo = function(){ } return { foo: foo } })() Module.foo()
3. 为什么要模块化
-
降低复杂度
-
提高解耦性
-
部署方便
4. 模块化的好处
- 避免命名冲突(减少命名空间的污染)
- 更好的分类,按需加载
- 更高的复用性
- 高可维护性
5. 模块的规范
- commenJS规范,node.js采用的规范
- AMD
- CMD
- ESModule(ES模块化)
6. Node.js模块化
- 采用commonjs模块系统
- 导入模块:require全局函数
- 导出模块:module.exports
- require方法导入本地的某个文件组件的话,一定要加上盘符前缀,即使在同一目录下
- node内部提供一个Module构建函数,所有的模块都是Module的实例
7. module对象
- module.id
模块的识别符,通常是带有绝对路径的模块文件名
- module.filename
模块的文件名,带有绝对路径
- module.loaded
返回一个布尔值,表示模块是否已经完成加载
- module.parent
返回一个对象,表示调用该模块的模块
- module.children
返回一个数组,表示该模块要用到的其他模块
- module.exports 表示模块对外输出的值
8. exports变量
-
为了方便,Node为每个模块提供了一个exports变量,指向module.exports,这等同于在每个模块头部,有一行这样的命令(只是等同于,并不是真的有该行代码)[参考指针作用]
var exports = module.exports
-
不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系
// 导出name变量 exports.name="张三" // 导出对象 let student = { name:'张三', age:18 } exports.student = student; // 对外输出模块接口时,可以向exports对象添加方法。 exports.eara = function(r){ return Math.PI*r*r; } exports.circumference = function(r){ return 2*Math.PI*r; } // 注意,不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系 exports = function(x){ console.log(x); }
var aa = require('./common') console.log(aa.name); var bb = aa.student console.log(bb); var box = aa.eara(5) console.log(box); var box2 = aa.circumference(2) console.log(box2); var f = aa console.log(aa);
9. require指令
- require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象,如果没有发现指定模块,就会得到一个空对象
- require命令用于加载文件,后缀名默认为.js,根据参数的不同格式,require命令去不同路径寻找模块文件
- 如果参数字符串以"/"开头,则表示加载的是一个位于绝对路径的模块文件
require('/user/cors/fun.js')
- 如果参数字符以"./"开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件
require('./fun.js')
- 如果参数字符串不以"./"或者"/"开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)
- 通常,我们会把相关的文件放在一个目录里面,便于组织,这时,最好为该目录设置一个入口文件,让require方法可以通过这个入口文件,加载整个目录。require发现参数字符串指向一个目录以后,会自动查看该目录的package.json文件,然后加载main字段指定的入口文件。
10. 模块的缓存
-
第一次加载某个模块时,Node会缓存该模块,以后再加载该模块,就直接从缓存中取出该模块的module.exports属性
上面代码中,连续三次使用require命令,加载同一个模块,第二次加载的时候为输出的对象添加了一个message属性,但是第三次加载的时候,这个message属性依然存在,这就证明require命令并没有重新加载模块文件,而是输出了缓存。
-
如果想要多次执行某个模块,可以让该模块输出一个函数,然后每次require这个模块的时候,重新执行一下这个输出的函数
-
所有缓存的模块都保存在require.cache中,如果想要删除模块的缓存,可以用下面的写法
-
注意,缓存时根据绝对路径来识别模块的,如果是同样的模块名,但是保存在不同的路径,require命令还是会重新加载该模块
11. 环境变量NODE_PATH
- node执行一个脚本时,会先查看环境变量NODE_PATH,它是一组以冒号分隔的绝对路径,在其他位置找不到指定模块时,可以将NODE_PATH添加到.bashrc
12. 模块的循环加载
-
如果发生模块的循环加载,即A既加载B,B又加载A,则B将加载A的不完整版本
-
require方法有一个main属性,可以用来判断模块是直接执行,还是被调用执行
- 直接执行的时候,require.main属性指向模块本身(node module.js)
require.main === module
- 调用执行的时候,返回false(通过require加载执行)
13. 模块的运行机制
- commonjs模块的加载机制
输入的是被输出的值的拷贝,也就是说,一旦输出一个值,模块内部的变化就是影响不到该值(仅仅是普通的值,如果是引用类型的值,还是会受影响的)
14. require的内部处理流程
-
require命令是commonjs规范中,用来加载其他模块的命令,它不是一个全局命令,而是指向当前模块的module.require命令,而后者又调用Node的内部命令Module._load
第四步,采用module.compile()执行指定模块的脚本
第一步和第二步,require函数执行如下:
- require():加载外部模块
- require.resolve():将模块名解析到一个绝对路径
- require.main:指向主模块
- require.cache:指向所有缓存的模块
- require.extensions:根据文件的后缀名,调用不同的执行函数
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!