node.js 模块及模块加载

node.js 模块

在node.js开发中,一个文件就可以认为是一个独立的模块

一、node.js模块分类

1、核心模块,也叫内置模块、原生模块

例如:fs,http,path,url

所有内置模块,在安装node.js的时候,就已经编译成 二进制文件,可以直接加载运行(速度较快)

部分内置模块,在node.exe这个进程启动的时候就已经默认加载了,所以可以直接使用

2、文件模块

按文件后缀来分

如果加载时,没有指定文件后缀名,那么,就按照如下顺序依次加载相应模块

(1).js

(2).json

(3).node (C/C++编写的模块)

3、自定义模块(第三方模块)

例如:mime、moment、cheerio等等

二、require加载模块的顺序

1、看 require() 加载模块时传入的参数是否以 '/' 或 './' 或 '../' 等等这样的路径方式开头(相对路径或绝对路径都可以)

2、如果是,就会按照传入的路径直接去查询对应的模块

(1)如果传入的为具体的文件名,例如:require('./test.js')

直接根据给定的路径去加载模块,找到了就加载成功,找不到加载失败

(2)如果传入的不是具体的文件名,例如:require('./test')

第一步:根据给定的路径,依次添加文件后缀.js、.json、.node进行匹配,如果匹配不到,执行第二步

第二步:查找是否有 test 目录(尝试寻找 test 包)

找不到:加载失败

找到了:依次在test目录下查找package.json文件(找到该文件后尝试找main字段中的入口文件)、index.js、index.json、index.node,找不到则加载失败

3、不是,那就认为传入的是“模块名称”,例如:require('http')、require('mime')

是核心模块,就直接加载核心模块

不是核心模块:

依次递归查找node_modules 目录中是否有相应的包

从当前目录开始,依次递归查找所有父目录下的node_modules 目录中是否包含相应的包

如果查找完毕磁盘根目录依然没有,则加载失败

打印输出module.paths查看

node.js 模块及模块加载

三、require函数加载模块原理(被加载的模块会先执行一次)

node.js 模块及模块加载

node.js 模块及模块加载

node.js 模块及模块加载

四、require加载模块注意点:

(1)所有模块第一次加载完毕以后都会有缓存,二次加载直接读取缓存,避免了二次开销。(因为有缓存,所以模块中的代码只在第一次加载的时候执行一次)

(2)每次加载模块的时候,都优先从缓存中加载,缓存中没有的情况下,才会按照node.js加载模块的规则去查找

(3)核心模块在node.js源码编译的时候,都已经编译成二进制执行文件,所以加载速度较快,核心模块加载的优先级仅次于缓存加载

(4)核心模块都保存在在 Node.js 源代码的 lib/ 目录下

(5)试图加载一个和核心模块同名的自定义模块(第三方模块)是不会成功的,因为存在同名模块的时候,require()总是会优先加载核心模块,这个情况下要使用自定义模块,要不名字不要与核心模块同名,要不就使用路径的方式加载

(6)核心模块 只能通过 模块名称来加载(错误的加载方式:require('./http');这样是无法加载 核心模块的http的)

(7)require()加载模块使用./相对路径时,相对路径是相对于当前模块,不受执行 node 命令的路径影响

(8)建议加载文件模块的时候始终添加文件的后缀名,不要省略

五、module.exports介绍

module.exports对象是由模块系统创建的,使用的时候,将期望导出的对象赋值给module.exports。

(1)module.exports用法

// a.js

function add(x, y) {
  return x+y;
}

var result = add (100, 10);
console.log(result);

module.exports = 'Hello World!';
// b.js

// 一个模块,默认被require()加载后,返回的是一个对象
// require()加载,是把a.js中module.exports这个对象的值赋值给a了

var a = require('./a.js');
console.log(a);

node.js 模块及模块加载 在b.js中  require()加载的过程,自动运行a.js代码,输出了110

(2)module.exports 只能导出一个对象

// a.js

module.exports = 'Hello World!';
module.exports = '666';
// b.js

var a = require('./a.js');
console.log(a);

node.js 模块及模块加载   module.exports对象 只能导出一个对象,后面的会覆盖前面的

(3)可以一个一个设置module.exports对象的属性值

// a.js

module.exports.name = 'Tom';
module.exports.age = 26;
module.exports.show = function () {
  console.log(this.name + this.age);
};
// b.js
// 一个模块,默认被require()加载后,返回的是一个对象
var a = require('./a.js');
console.log(a);
// 调用a中的方法
a.show();

node.js 模块及模块加载

(4)改变module.exports 的属性值

// a.js

module.exports = {
  text:'Hello World!',
  age: 12,
  show: function () {
    console.log(this.text + '你好');
  }
};

module.exports.name = 'Tom';
module.exports.age = 26;
module.exports.show = function () {
  console.log(this.name + this.age);
};
// b.js
// 一个模块,默认被require()加载后,返回的是一个对象
var a = require('./a.js');
console.log(a);
// 调用a中的方法
a.show();

node.js 模块及模块加载

六、exports和module.exports的区别

(1)exports 是 module.exports 的一个快捷方式

exports 变量是在模块的文件级别作用域内有效的,它在模块被执行前被赋予 module.exports 的值。

它有一个快捷方式,以便 module.exports.f = ... 可以被更简洁地写成 exports.f = ...

就是说:exports 是 module.exports 的一个快捷方式

// a.js

module.exports.name = '张三';
exports.age = 18;
exports.show = function () {
  console.log(this.name + this.age);
};
// b.js

var a = require('./a.js');
console.log(a);
// 调用a中的方法
a.show();

node.js 模块及模块加载

(2)exports 和 module.exports 指向的是同一个对象

// a.js

module.exports.name = '张三';
// exports 是 module.exports 的一个快捷方式
exports.age = 18;
exports.show = function () {
  console.log(this.name + this.age);
};

console.log(module.exports);
console.log(exports);

node.js 模块及模块加载

(3)如果一个新的值被赋值给 exports,它就不再绑定到 module.exports

// a.js

module.exports.name = '张三';

exports.age = 18;
exports.show = function () {
  console.log(this.name + this.age);
};
// 一个新的值被赋值给 exports,它就不再绑定到 module.exports 
exports = {text: 'hello'};
exports.gender = '男';
console.log(module.exports);
console.log(exports);
// b.js

var a = require('./a.js');
console.log(a);

node.js 模块及模块加载

(4)require() 函数返回的是 module.exports 中的数据

当 module.exports 属性被一个新的对象完全替代时,最终 require() 函数返回的是 module.exports 中的数据

// a.js

module.exports.name = '张三';
exports.age = 18;
exports.show = function () {
  console.log(this.name + this.age);
};
module.exports = 'Hello World!';
// b.js

var a = require('./a.js');
console.log(a);

node.js 模块及模块加载

node.js 模块及模块加载