Node04 模块化

重新学习Node,整理以前的日志。Node中模块化的学习笔记。

几种形式

模块导入和导出有几种形式:

  1. require:Node和ES6都支持的引入
  2. export/import:只有ES6支持的导出/引入格式
  3. module.exports/exports:只有Node支持的导出格式

Node

Node的模块系统遵循的是CommonJS规范,CommonJS定义的模块分为模块标识(module)、模块定义(exports)、模块引用(require

exportsmodule.exports

Node在执行一个文件时,会给这个文件内生成一个exportsmodule对象,module又有一个exports属性,他们的关系如下,都指向一个内存区域:

1
exports = module.exports = {};

内存结构示意图

如果人为将二者指向不同的内存区域,最终导出的内容是module.exports的内容,而不是exports的内容,所以尽量都使用module.exports导出,用require导入

require

Node.js提供了exportsrequire两个对象,其中exports是模块公开的接口,require用来从外部获取一个模块接口,即获取模块的exports对象。

Node.js可以加载的文件模块分为三种:

  • .js,通过fs模块同步读取JS文件并编译执行
  • .node,通过C/C++进行编写的Addon。通过dlopen方法进行加载
  • .json,读取文件,调用JSON.parse解析加载

require可以接受以下几种参数的传递:

  • lodashjQuery等原生模块
  • 相对路径的文件模块
  • 绝对路径的文件模块
  • 非原生模块的文件模块

在引用文件模块的时候后要加上文件的路径:

  • /.../.../xxx.js表示绝对路径、
  • ./xxx.js表示相对路径(同一文件夹下的xxx.js)
  • ../表示上一级目录
  • 如果既不加/.../、../又不加./的话,则该模块要么是核心模块,要么是从一个node_modules文件夹加载

小例子

test1.js文件:

1
2
3
4
5
6
7
8
9
10
const tt1 = function (a, b) {
return a + b;
};

function tt2(a, b) {
return a * b;
}

module.exports.tt1 = tt1;
module.exports.tt2 = tt2;

test2.js文件

1
2
3
4
const test1 = require("./test1.js");

console.log(test1.tt1(1, 2));//3
console.log(test1.tt2(1, 2));//2

在命令行执行

1
node test2.js

上面代码要注意:

  1. 被引用的test1.js需要将要导出的对象存入module.exports(或者是exports)中
  2. test2.js文件中引入test1.js的结果,引入的就是module.exports对象,该对象对应的方法就是在test1.js中定义的函数
  3. 在使用require时要表明路径,否则会找不到对应的文件。

ES6的模块化

ES6中的规范是使用exportimport来导出和导入模块

导出的时候有的时候会增加一个default关键字,它其实就是一个语法糖:

1
2
3
4
5
6
// test.js
const a = 123;

export default a

// 等同于 export { a as default }

引入的时候就可以直接使用任意变量名引入:

1
2
3
import x from './test.js'

// 等同于 impor { default as x } from './test.js'

要注意的是一个模块里面只能有一个export default

还要注意,ES6导出的模块是静态的,我是这样理解的:导出的只是一段代码,并没有实际运行,导出的如果是函数也没有执行

参考