node.js中exports与module.exports的区别分析

我们在使用node.js中经常会使用到exports和module.exports对模块中的方法进行导出,在其他模块进行使用。但是他们会有什么区别呢?或者说我们有了解模块吗?本文主要介绍一下Module模块

 

一 、模块是什么?

 

在js的源码load.js中,我们可以看到模块其实是一个Module对象。

function Module(id = '', parent) {
  this.id = id;
  this.path = path.dirname(id);
  this.exports = {};
  this.parent = parent;
  updateChildren(parent, this, false);
  this.filename = null;
  this.loaded = false;
  this.children = [];
}

解析:

module.id 模块的识别符,通常是带有绝对路径的模块文件名。

module.filename 模块的文件名,带有绝对路径。

module.loaded 返回一个布尔值,表示模块是否已经完成加载。

module.parent 返回一个对象,表示调用该模块的模块。

module.children 返回一个数组,表示该模块要用到的其他模块。

module.exports 表示模块对外输出的值。

 

二、 require的模块加载机制

我们经常会使用require在某个文件中引入其他模块中exports和module.exports的方法,下面我们通过源码来了解一下require。首先require在源码中调用的 Module._load 方法。

// require 其实内部调用 Module._load 方法
Module._load = function(request, parent, isMain) {
  //  计算绝对路径
  var filename = Module._resolveFilename(request, parent);

  //  第一步:如果有缓存,取出缓存
  var cachedModule = Module._cache[filename];
  if (cachedModule) {
    return cachedModule.exports;

  // 第二步:是否为内置模块
  if (NativeModule.exists(filename)) {
    return NativeModule.require(filename);
  }
  
  /********************************这里注意了**************************/
  // 第三步:生成模块实例,存入缓存
  // 这里的Module就是我们上面的1.1定义的Module
  var module = new Module(filename, parent);
  Module._cache[filename] = module;

  /********************************这里注意了**************************/
  // 第四步:加载模块
  // 下面的module.load实际上是Module原型上有一个方法叫Module.prototype.load
  try {
    module.load(filename);
    hadException = false;
  } finally {
    if (hadException) {
      delete Module._cache[filename];
    }
  }

  // 第五步:输出模块的exports属性
  return module.exports;
};

 

总结:requre主要是通过文件的路径 - 找到对应的Module对象(没有则创建)- 返回对应module对象的exports对象。

三、exports和module.exports

 

结论就是

1.exports其实是指向module.exports的。

2.exports和module.exports都是往对应的Module对象的exports对象中添加数据。

3.module.exports可以直接导出一个对象或者一个常量等

module.exports = {
    test:"test"
};


module.exports = "123"

module.exports = new hello()

 

在开发Node.js应用的时候,很多模块都是需要引入才能使用,但是为什么exports和module.exports我们没有引用却可以直接使用呢?

 

事实上,Node.js应用在编译的过程中会对JavaScript文件的内容进行头尾的封装。例如:

// hello.js
const hello = function () {
	console.log('Hello world');
}
module.exports = {
	hello
}
// 头尾封装后的js代码
(function (exports, require, module, __filename, __dirname) {
    const hello = function () {
        console.log('Hello world');
    }
    module.exports = {
        hello
    }
})

在进行了头尾封装之后,各个模块之间进行了作用域隔离,避免了污染全局变量,同时可以使每个模块在不引入这些变量的情况下可以使用它们。这些变量依次为当前模块的exports属性、require()方法、当前模块自身(module)、在文件系统中的完整路径、文件目录。

 

//hello.js
const hello = function () {
    console.log('Hello world');
}

module.exports = {
    hello
}

console.error(module);

 

Module {

id: '.',

exports: { hello: [Function: hello] },

parent: null,

filename: 'C:\\Users\\WebstormProjects\\study\\bin\\hello.js',

loaded: false,

children: [],

paths:

[ 'C:\\Users\\WebstormProjects\\study\\bin\\node_modules',

'C:\\Users\\WebstormProjects\\study\\node_modules',

'C:\\Users\\WebstormProjects\\node_modules',

'C:\\Users\\node_modules',

'C:\\Users\\node_modules',

'C:\\node_modules' ] }

调用文件:

//1212.js
var test = require("./hello").hello;

test();

console.error(module);

 

Hello world

Module {

id: '.',

exports: {},

parent: null,

filename: 'C:\\Users\\WebstormProjects\\study\\bin\\1212.js',

loaded: false,

children:

[ Module {

id: 'C:\\Users\\WebstormProjects\\study\\bin\\hello.js',

exports: [Object],

parent: [Circular],

filename: 'C:\\Users\\WebstormProjects\\study\\bin\\hello.js',

loaded: true,

children: [],

paths: [Array] } ],

paths:

[ 'C:\\Users\\WebstormProjects\\study\\bin\\node_modules',

'C:\\Users\\WebstormProjects\\study\\node_modules',

'C:\\Users\\WebstormProjects\\node_modules',

'C:\\Users\\node_modules',

'C:\\Users\\node_modules',

'C:\\node_modules' ] }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值