node.js模块机制

模块化的作用是可以让代码更易于管理。下面开发2个模块,然后用主程序加载这2个模块。

main.js

// math.js
// 加法
exports.add = function(a,b){
   return a+b;
}
// 减法
exports.cut = function(a,b){
   return a-b;
}

math2.js

module.exports = {

  // 除法
  division:function(a,b){
    return a/b;
  },

  // 乘法
  multipli:function(a,b){
    return a*b;
  }

}

main.js

// 加载math模块
var math = require("./math");
// 加载math2模块
var math2 = require("./math2");

console.log(math.add(6,3));         // 9
console.log(math.cut(6,3));         // 3
console.log(math2.division(6,3));   // 2
console.log(math2.multipli(6,3));   // 18

main.js是主程序,通过require加载模块,exports 和 module.exports 是模块的出口,exports 是 module.exports 的辅助写法,module.exports = xxx 这种写法是合法的,而exports = xxx这种写法是错误的,exports.xxx = xxx这种写法才是合法的。

如果定义的模块中同时使用 moudle.exports 和 exports ,那么会忽略exports的定义,看下面的代码。

修改后的math2.js

// 修改后的math2.js
exports.division = function(a,b){
    return "-----";
}

module.exports = {

  // 除法
  division:function(a,b){
    return a/b;
  },

  // 乘法
  multipli:function(a,b){
    return a*b;
  }

}

exports.division = function(a,b){
    return "-----";
}

主程序 main.js

//主程序 main.js
// 加载math模块
var math = require("./math");
// 加载math2模块
var math2 = require("./math2");

console.log(math.add(6,3));
console.log(math.cut(6,3));
console.log(math2.division(6,3));  // 2
console.log(math2.multipli(6,3));

运行后会发现,exports.division在遇到module.exports时会无效。

知道如何定义模块后,回过头来看看模块的分类,模块分为核心模块,文件模块。

核心模块

核心模块就是核心库,例如http模块,当通过require("http")模块时,即使自己定义了http模块,但系统还是会返回核心模块。

文件模块

除了核心模块,都是文件模块,也就是自己定义的模块文件。

文件模块的位置

加载文件模块可以采用绝对路径,相对路径和node_modules目录下。

相对路径和绝对路径这里就不解释了,node_modules目录下的意思是require会先查找当前目录下是否有 node_moudules目录,如果有会先在这个目录查找模块,如果没有再向上级目录找是否有node_moudles目录一直到根目录,如果都没有会抛出异常。如果把模块放在node_moudles目录下,那么采用require("modulename")写法和加载核心目录的写法一致,这个要区别于相对目录的require("./modulename")写法。

文件模块的扩展名

require("./test.js") 如果写了完整的文件名会准确加载这个文件,如果没有写入扩展名require("./test"),那么会尝试加载 test.js 然后是test.json。 系统会把test.js解析为一个js文件,而会把test.json解析为一个json文件。

package.json 定义包

在main.js启动文件的当前目录下,创建一个mymodule的文件夹。该目录下创建一个package.json,内容如下:

{
    "name":"math",
    "main":"./math.js"
}

然后在package.json统计目录下顶一个math.js文件。

exports.add = function(a,b){
    return a+b;
}
exports.cut = function(a,b){
    return a-b;
}

然后main.js主文件加载mymoudle模块。

var math = require("./mymodule");

如果在mymodule目录下找不到package,会尝试找mymodule/index.js文件加载。

god模块加载就讲这么多,多练习掌握模块加载的规律就熟了。下一节探讨一下module的属性和方法。

module的属性与方法

module.exports

上一节已有详细介绍,但要注意一点,module.exports 必须要立即执行,否则模块不会被加载,看下面代码:

setTimeout(function() {
 module.exports = { a: "hello" };
}, 0);

以上模块不会被加载。

module.require(id)

require是module.require的简写方式。

module.id

模块文件的完整路径,main.js如果是主启动文件,那么它自身调用 console.log(module.id) ,只会打印出 "." 。

module.filename

这个和module.id功能一样,即使是main.js调用console.log(module.filename)也会打印出完整的文件路径。

module.loaded

判断模块是否被加载完成,true/false。

module.parent

得到父模块。

module.children

得到子模块。