什么是CommonJS?Nodejs中如何自定义模块?

1. 什么是CommonJS?

CommonJS是一种模块化解决方案,为JavaScript语言提供了一种通用的模块标准。它被广泛应用于服务器端JavaScript开发中,而Nodejs正是基于CommonJS规范来实现模块化编程的。

在CommonJS规范中,一个模块就是一个JavaScript文件,定义了一组函数、对象或者变量,这些函数、对象或者变量可以被其他模块调用。同时,每个模块都有自己的作用域,在该作用域内定义的变量和函数在模块外是不可见的,这样就避免了全局变量的污染。

在 CommonJS 规范中,每个模块都是一个单独的文件,它们的模块名对应于文件名。模块可以通过 require 方法来加载其他模块,也可以通过 exports 对象来将模块中的数据或方法暴露给外部使用。

// 定义一个模块,导出一个 power 函数

function power(x, n){

return Math.pow(x, n);

}

exports.power = power;

// 加载模块并使用其导出的 power 函数

var calc = require('./calc.js');

var result = calc.power(2, 3); // 8

2. Nodejs中如何自定义模块?

2.1 模块导出

在Node.js中,我们通过 module.exportsexports 来实现模块的导出。两者区别如下:

exports 是 module.exports 的一个引用,最终导出的是 module.exports

如果直接给 exports 赋值,则会断开其和 module.exports 的引用关系,从而导致模块导出失效。

// 导出一个变量

exports.name = 'Node.js';

// 导出一个函数

module.exports.add = function(a, b){

return a + b;

}

// 导出一个类

class Person{

constructor(name, age){

this.name = name;

this.age = age;

}

sayHi(){

console.log('Hi, my name is ' + this.name + ', I am ' + this.age + ' years old.');

}

}

module.exports.Person = Person;

2.2 模块加载

在Node.js中,我们通过 require 方法来加载其他模块,具体使用如下:

// 加载一个变量

var name = require('./name.js').name;

// 加载一个函数

var add = require('./math.js').add;

// 加载一个类

var Person = require('./person.js').Person;

2.3 模块路径

在使用 require 方法加载模块时,需要指定模块的路径,具体如下:

如果指定的是一个相对路径,则该路径以当前模块所在目录作为相对路径的起点。

如果指定的是一个绝对路径,则该路径以当前根目录作为路径的起点。

如果指定的路径不是一个相对路径或绝对路径,则Node.js会从当前模块的 node_modules 目录下查找相应的模块。

// 加载当前目录下的 ./math.js

var math = require('./math.js');

// 加载上级目录下的 ./config.js

var config = require('../config.js');

// 加载其他模块的 /Users/username/node_modules/request/request.js

var request = require('request');

2.4 模块缓存

在Node.js中,每个模块都会被缓存起来,这样可以避免重复加载同一个模块,提高程序的性能。而当我们在程序运行时进行代码修改后,这些修改并不会立即生效,因为Node.js会缓存之前加载过的模块。

要想让修改生效,我们可以采取以下方法之一:

退出当前的Node.js进程,重新启动程序;

使用Node.js内置的模块 fs 监听文件修改事件,当文件变化时强制清空模块缓存重新加载。

// 监听文件修改事件,强制清空缓存

var fs = require('fs');

fs.watch('./math.js', function(){

delete require.cache[require.resolve('./math.js')];

});

2.5 模块循环依赖

在Node.js中,循环依赖是一种常见的问题。它指的是模块A依赖于模块B,而模块B又依赖于模块A,从而导致无法正常加载。

为了解决这个问题,Node.js采取了一种特殊的处理方式:

在执行A模块之前,先将A模块标记为已经加载,然后将exports对象传入A模块所依赖的模块B;

当执行B模块时,发现B模块依赖于A模块,但是A模块已经被加载了,此时直接从缓存中获取A模块的exports对象;

当A模块执行完毕后,将A模块的exports对象返回给B模块继续执行,这样就避免了循环依赖的问题。

虽然Node.js通过特殊处理避免了循环依赖的问题,但是在开发过程中还是应该尽可能避免模块之间的循环依赖,以减少程序的复杂度。

2.6 模块的加载顺序

在Node.js中,模块的加载顺序是按照以下规则进行的:

首先在当前目录下查找模块,如果找不到,则继续往上级目录查找,直到找到为止;

如果找到同名的目录和模块,优先加载目录。

如果在同一级目录下同时存在 index.jsindex.json 文件,Node.js会优先加载 index.js 文件。

如果直接指定了一个文件夹作为模块名,则Node.js会先在该文件夹下查找 package.json 文件,读取其中的 main 属性指定的文件作为入口文件;如果不存在 package.json 文件或者 main 属性不存在,则默认加载 index.js 文件。

需要注意的是,模块的加载顺序是非常重要的,因为它决定了程序的正确性和性能。

2.7 模块覆盖与覆盖范围

在Node.js中,模块可以被其他模块覆盖。当一个模块被覆盖时,覆盖的范围取决于何处进行了模块覆盖。

模块覆盖分以下两种情况:

全局模块覆盖:当我们在程序中使用 require 方法加载一个模块时,Node.js会从以下两个位置查找模块:

全局模块,即在命令行中使用 -r 参数加载的模块;

当前目录下的 node_modules 目录(或其他指定的模块路径)中的模块。

局部模块覆盖:当在模块内部覆盖另一个模块时,它会影响到所有使用该模块的代码,因为在Node.js中模块只会被加载一次,并且被缓存起来。

需要注意的是,在开发过程中不要随意覆盖模块,因为这样会导致代码的可维护性和可读性大大降低,这对于大型项目来说是无法承受的。

总结:Node.js 中的模块化开发是非常重要的,而 CommonJS 规范则是 Node.js 支持的模块化规范。在实际的应用中,我们需要遵循一定的规范来实现模块化管理,这样可以避免代码的混乱和冗余,提高代码的可维护性。

免责声明:本文来自互联网,本站所有信息(包括但不限于文字、视频、音频、数据及图表),不保证该信息的准确性、真实性、完整性、有效性、及时性、原创性等,版权归属于原作者,如无意侵犯媒体或个人知识产权,请来电或致函告之,本站将在第一时间处理。猿码集站发布此文目的在于促进信息交流,此文观点与本站立场无关,不承担任何责任。