Nodejs模块化开发

前言

对nodejs入门之后,我们经常会发现,代码中经常会出现require(’’)这样的代码,nodejs菜鸟教程的创建的第一个应用就使用到了require指令来载入http模块,并将实例化的http赋值给变量http。那么所谓的模块又是什么?今天将从require开始,进入模块的世界

require(’’)方法

require()是接收模块标识符参数,然后node根据一定的规则引入该模块之后,就可以使用模块中定义的方法和属性了。node引入模块是有规则的。
nodejs模块包含三种:
内置模块:也就是nodejs提供的模块,例如http,fs等。这些模块在node源码编译的过程中就编译进了二进制执行文件,在node进程启动的时候,部门核心模块就直接加载进内存中,只需要经历路径分析步骤,而且路径分析中是有限判断的,所以加载速度较快。
第三方模块:
自定义模块(一个js一个模块):文件模块使用的时候需要按需加载,需要经历路径分析、文件定位、编译执行三个步骤。

优先从缓存中加载

node对引入过的模块会进行缓存,node是缓存编译执行之后的对象而不是静态文件,是因为 我们对一个对象引入两次,得到的对象是相等的。跟Java不同,如果你对Java的一个对象new两次,那么你得到的是两个不同的对象。
验证代码如下:
module.js

let sayHello=function(){
    console.log('hello');
}

let sayBye=function(){
    console.log('Bye~');
}

module.exports={
    sayHello:sayHello,
    sayBye:sayBye
}

testmodule.js

var moduleTest1=require('./module1');
var moduleTest2=require('./module1');

console.log(moduleTest2);
console.log(moduleTest1===moduleTest2);

运行结果如下:
在这里插入图片描述
解析:虽然我们两个引入了module1的模块,但是模块中的代码其实只执行了一遍。那么moduleTest1和moduleTest2指向的是同一个对象,结果才会是TRUE。–可以查看Module._load的源码进行分析

路径分析

nodejs会根据require是相对路径还是非相对路径做出不同的行为。
require(Y+X)
1、如果X是核心模块,例如(require(“http”))
* 返回该模块 * 不在继续执行
2、如果Y是以’./’,’/‘或者’…/‘开头
(1)优先从缓存中加载
(2)X当做文件,从制定路径开始,依次查找下面文件:X、X.js、X.json、X.node,只要其中一个存在,就返回该文件,不在继续执行
(3)把X当成目录,从执行路径开始,一次查找下面文件:X/package.json(main字段)、X/index.js、X/index.json、X/index.node,只要其中一个存在,就返回该文件,不在继续执行
3、如果X不是核心模块,也没有’./’,’/‘或者’…/'开头,则nodejs会从当前模块的父目录开始,尝试从它的/node_module目录里加载模块,如果还没有找到,则移动到再上一层父目录,直到文件系统的根目录。
4、抛出Error: Cannot find module

清除缓存

require第一步是将模块加载到内存的,用于提升第二次加载的性能。但是,如果修改了被引入模块的代码之后,再次引入,就发现还是之前的代码。

module模块

每个文件就是一个模块,每个模块中都有一个module对象。module对象的属性以下图片是打印出来的module对象值:
在这里插入图片描述
由图可知,module对象有以下属性
(1)id:当前模块的bi
(2)path:文件所在位置
(3)exports:暴露给外部的值,由代码值,此暴露了2个函数
(4)parent:一个对象,表示调用当前模块的模块
(5)filename:模块的绝对路径
(6)loaded:布尔值,表示当前模块是否已经被完全加载
(7)paths:从当前文件目录开始查找node_modules目录;然后依次进入父模块,查找父目录下的node_modules目录,直到根目录下的node_modules目录。

module.exports

经过上面的解析,发现nodule对象有一个exports属性,该属性就是用来对外暴露变量、方法或这个模块的。当使用require调用的时候,其实就是调用的exports属性

exports对象

module.exports和exports对象的联系和区别:
1、module.exports和exports对象的都是引用类型的变量,两个对象指向同一块内存地址。并且两者一开始都是指向一个空对象
2、exports只能使用,语法类向外暴露内部变量 export.xxx=xxx,而module.exports可以使用语法或者对象的形式输出

module.exports.xxx=xxx;
module.exports={xxx:yyy}

如果以对象输出的的话只能module.exports

3、module对象中包含了exports对象,所以exports不能直接赋予对象类型的值,因为这样会改变exports的指向,从而找不到module.exports和exports不是一个对象,也就是说给exports赋值会切断与module.exports之间的联系
在这里插入图片描述
tips:exports=module.exports=xxx //code
这种方式的实现其实就是赋值module.exports后不忘把exports也同时指向这块新内存了,即module.exports指向新对象以后,exports断开了对module.exports的引用,后面的做法主要是让exports重新指向module.exports

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章