更新于 

模块化

模块化简介

Node中,一个js文件就是一个模块。

require

node使用require引入外部模块,
注意:如果要使用相对路径,必须以.或..开头
require引入模块之后会返回一个对象,该对象表示的是引入的模块。

require引入

运行命令

node helloNode.js

运行结果

module A
hello node

helloNode.js

1
2
require('./module');
console.log("hello node");

module.js

1
console.log("module A");
exports暴露变量

Node中,每个js文件中的js代码实际上都相当于运行在一个独立的函数之中。

1
2
3
(function(){
// 函数体
})()

可以通过exports来向外暴露变量。

1
exports.variableName
exports案例

helloNode.js

1
2
3
let module_prop =  require('./module');
console.log(module_prop.a,module_prop.b);
module_prop.fun(10,5);

module.js

1
2
3
4
5
exports.a = 123;
exports.b= "abc";
exports.fun = function(num1,num2){
console.log(num1+num2);
}

node helloNode.js
运行结果:
123 abc
15

模块化详解

模块标识

使用require引入模块的时候,使用的就是模块标识,
模块标识能用来找到指定模块。
模块标识分为两大类:

  • 核心模块
    • 由node引擎提供的模块
    • 核心模块的表示就是模块名
      1
      let fs = require("fs")
  • 文件模块
    • 由用户自己创建的模块
    • 文件模块的标识就是文件的路径(绝对路径、相对路径)
      1
      let math = require("./math")
全局对象global

node中有一个全局对象global,作用和window类似,
全局中创建的变量和函数都会作为global的方法和属性保存。
不使用let/var定义的变量即全局变量:

1
2
3
4
let a = 10;
global_a = 100;
console.log(global.a); //undefined
console.log(global.global_a); //100
node对模块的函数化包装

如何确定我们调用的js文件实际上是函数呢?
可以使用js中函数独有的arguments.callee属性,
这个属性描述的是正在调用的函数体

执行代码

1
2
let a = 10;
console.log(arguments.callee + "");

输出结果

1
2
3
4
function(exports, require, module, __filename, __dirname) {
let a = 10;
console.log(arguments.callee + "");
}

node模块化正是对每个js模块文件中的执行代码进行函数包装操作:

1
2
3
function(exports, require, module, __filename, __dirname){
// 我们自己的js代码像奥利奥夹心一样被夹在这里
}

这同是也解释了我们之前使用的exports和require的来源,它们都是被包装的函数传进来的参数。

  • exports
    • 用于将变量或函数暴露到外部
  • require
    • 函数,用于引入外部模块
    • require函数代码
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      [Function: require] {
      resolve: [Function: resolve] { paths: [Function: paths] },
      main: Module {
      id: '.',
      path: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module',
      exports: {},
      filename: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\main.js',
      loaded: false,
      children: [],
      paths: [
      'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\node_modules',
      'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\node_modules',
      'D:\\CS_Demo\\V_Demo\\node_modules',
      'D:\\CS_Demo\\node_modules',
      'D:\\node_modules'
      ]
      },
      extensions: [Object: null prototype] {
      '.js': [Function (anonymous)],
      '.json': [Function (anonymous)],
      '.node': [Function (anonymous)]
      },
      cache: [Object: null prototype] {
      'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\main.js': Module {
      id: '.',
      path: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module',
      exports: {},
      filename: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\main.js',
      loaded: false,
      children: [],
      paths: [Array]
      }
      }
      }
  • module
    • 代表当前模块自身
    • exports就是module的属性,用exports和module.exports本质上没有区别
      1
      console.log(Object.is(module.exports,exports)); //true
    • module对象源码
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      Module {
      id: '.',
      path: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module',
      exports: {},
      filename: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\main.js',
      loaded: false,
      children: [],
      paths: [
      'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\node_modules',
      'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\node_modules',
      'D:\\CS_Demo\\V_Demo\\node_modules',
      'D:\\CS_Demo\\node_modules',
      'D:\\node_modules'
      ]
      }
  • __filename
    • 当前模块的完整路径
  • __dirname
    • 当前模块所在文件夹的完整路径
module.exports和exports的区别

对于暴露单个属性或方法,使用module.exports和exports都是一样的:

math.js

1
2
3
4
5
6
7
8
exports.pi = 3.14;
module.exports.sin90 = 1;
exports.add = function(num1,num2){
return num1+num2;
}
module.exports.multiply = function(num1,num2){
return num1*num2;
}

main.js

1
2
3
4
5
let math = require('./math');
console.log(math.pi); //3.14
console.log(math.sin90); //1
console.log(math.add(10,5)); //15
console.log(math.multiply(2,4)); //8

但是如果将需要将对象和方法包装成类暴露的话,
通过module.exports可以直接赋值,
而直接修改exports相当于修改exports的指向,切断了它和module之间的指向关系。

1
2
3
4
5
6
7
8
9
10
module.exports = {
pi:3.14,
sin90:1,
add:function(num1,num2){
return num1+num2;
},
multiply:function(num1,num2){
return num1*num2;
}
}