[NodeJS]Node模块原理

时间:2021-10-30 22:13:28

      任何一门编程语言,当代码越写越多时,人们就会考虑如何将代码进行分类组织。通常情况下,都会讲代码按照功能进行拆分并保存在不同目录及文件中,通过相互引用来达到代码复用。那么这个时候不可避免的就会遇到全局变量可能会被污染的问题。通常情况下,很多语言都会提供一个叫做命名空间的概念,从而形成了模块这个概念。然而JS天生并没有提供命名空间这样一个机制。于是有热心的开发者提供了CommonJS和AMD,CMD等多种规范。其中NodeJS就是遵循CommonJS规范的。而现在ES6也已经推出,它提供的模块机制是综合了各家的优势后设立的另一套规范。

      现在我们来细细聊NodeJS中的模块机制。在NodeJS中,Node模块允许开发者从被引入的文件中选择要暴露给外界的函数或变量。机制是通过exports对象的属性或module.exports属性进行模块暴露。NodeJS模块系统正是通过这样一种机制来避免了全局作用域的污染,从而避免了命名冲突。接下来从几个方面来讲解模块。

一、创建模块

      NodeJS中的模块可以是一个文件,也可以是一个包含多文件的目录。如果模块是一个目录,那么Node就会在该目录下查找一个叫index.js的文件作为模块的入口。当然这个文件名index.js也是可以通过package.json文件进行配置的。通过在exports对象上设置属性的方式来创建模块。

var canadianDollar = 0.91;
function roundTwoDecimals(amount){
    return Math.round(amount*100)/100;
}
exports.canadianToUS = function(canadian){
    return roundTwoDecimals(canadian * canadianDollar);
}
exports.USToCanadian = function(us){
    return roundTwoDecimals(us / canadianDollar);
}

通过require(path)的方式来加载模块。注意如果是自定义文件模块并且处在同一目录下,那么一定要记住请使用 " ./ " 这个相对路径标识。

var currency = require('./currency');
console.log("50 Canadian dollars equals this amount of US dollars:");
console.log(currency.canadianToUS(50));
console.log("30 US dollar equals this amount of Canadian dollars:");
console.log(currency.USToCanadian(30));

也可以通过module.exports来创建模块

function Currency(canadianDollar){
    this.canadianDollar = canadianDollar;
}
Currency.prototype.roundTwoDecimals = function(amount){
    return Math.round(amount*100)/100;
};
Currency.prototype.canadianToUS = function(canadian){
    return this.roundTwoDecimals(canadian * this.canadianDollar);
};
Currency.prototype.USToCanadian = function(us){
    return this.roundTwoDecimals(us / this.canadianDollar);
};
module.exports = Currency;

这样通过require方法引入的模块就是一个构造函数

var Currency = require("./currency");

var canadianDollar = 0.91;
var currency = new Currency(canadianDollar);
console.log(currency.canadianToUS(50));

模块最终导出的是module.exports对象,而模块内部隐藏了一句代码exports = module.exports 所以不要轻易给exports重新设置引用关系。

module对象在所有的Node程序中都存在,但是每个module对象都仅仅存在于它当前的模块内。也就是说只存在于模块作用域内。

 

二、安装与加载模块

从npm安装第三方模块使用  npm install [package] 命令

通过require() 来加载模块

通过npm search [package] 命令来查找模块

同理,require对象也不是全局变量,而是每个模块内部的一个对象,作用于模块内。

require对象的方法

1. require.cache

当模块被引入时,会被缓存到这个对象中,通过 delete 可以从该对象中删除键值,这样下次调用 require()时就会重新加载模块。不适用于核心模块,常用于第三方模块。

2. require.resolve()

使用内部的require()机制来查找模块的位置,但是不会加载模块,只是返回解析后的模块文件绝对路径( __filename )。这个绝对路径也是module对象中的Id属性。

 

模块加载的内部原理

通常在package.json文件中会通过main属性来指定模块入口文件,这样加载模块时会考虑这个默认文件。