图文揭秘Node.js中exports和module.expor

作者: winwill2012 | 来源:发表于2015-11-12 13:03 被阅读551次

概述

首先我们得先摆出两条不变的真理:

  1. exports一开始是指向module.exports的;
  2. 通过require得到的是module.exports中的内容,而不是exports的内容;

详解

exports和module这两个对象是所有Node.js类型的文件中都默认隐式存在的,比如我们新建一个test.js文件:

console.log(exports);
console.log(module);

在终端运行:

[qifuguang@Mac~/nodejs/learnModule]$ node test.js
{}
Module {
  id: '.',
  exports: {},
  parent: null,
  filename: '/Users/qifuguang/nodejs/learnModule/test.js',
  loaded: false,
  children: [],
  paths:
   [ '/Users/qifuguang/nodejs/learnModule/node_modules',
     '/Users/qifuguang/nodejs/node_modules',
     '/Users/qifuguang/node_modules',
     '/Users/node_modules',
     '/node_modules' ] }

可以看到,test.js文件中并未声明exports和module对象,但是它们确实存在。并且可以看到,exports的初始值是{},而module的初始值有一大串属性,其中还包含一个exports属性,它的初始值也是{}。

实际上,一开始exports就是指向module.exports的,引用关系如下图:



请牢记这个引用图,之后的分析都依靠这个图。

我们再举个例子,创建如下的my_module.js文件:

exports.sayHello = function() {
    console.log('Hello world!');
}

再在同一个目录下创建app.js文件:

myModule = require('./my_module');
myModule.sayHello()

在终端运行app.js:

[qifuguang@Mac~/nodejs/learnModule]$ node app.js
Hello world!

现在我们分析一下为什么会有这样的输出结果:
在app.js文件中我们使用require语句从my_module.js模块中得到了module.exports,这里的module.exports的内容是什么呢?

在my_module.js文件中我们在exports的基础上为它添加了一个属性sayHello,这个属性的值是一个函数,并且因为初始时,exports指向的是module.exports,他俩共享同一块内存,所以这个操作后,module.exports变成了这样:



所以,app.js文件中的myModule变量的值为:

{
    sayHello: function() {console.log('Hello world');}
}

于是,很自然地,我们可以使用myModule.sayHello调用它对应的函数,输出熟悉的Hello world字符串。

再举个例子,我们将my_module.js文件修改为如下内容:

exports = {
    sayHello: function() {console.log('Hello world!');}
}

然后将app.js文件修改为如下内容:

myModule = require('./my_module');

console.log('module.exports:');
console.log(module.exports);

myModule.sayHello()

然后一样在终端运行:

[qifuguang@Mac~/nodejs/learnModule]$ node app.js
module.exports:
{}
/Users/qifuguang/nodejs/learnModule/app.js:6
myModule.sayHello()
         ^

TypeError: myModule.sayHello is not a function
    at Object.<anonymous> (/Users/qifuguang/nodejs/learnModule/app.js:6:10)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:311:12)
    at Function.Module.runMain (module.js:467:10)
    at startup (node.js:136:18)
    at node.js:963:3

可以看到,报错了,报错了,报错了!

分析一下原因:
my_module.js文件中将exports重新赋值为一个新的对象,这就相当于Java中的

Object newObje = new Object();

一样,这个时候exports将会自己分配一块新的内存,而不再指向module.exports了,所以这个时候exports和module.exports彻底断绝关系,无论你怎么蹂躏(操作)exports对象,都与module.exports无关了。

所以,my_module.js文件中为exports对象重新赋值之后,exports和module.exports的状态是这样的:


从输出中也可以看到,此时的module.exports={},所以肯定找不到sayHello函数,那必然报错!

其他的我也不多说了,根据这两个例子与这两幅图,我相信更多的情况大家都会自己分析了。

声明

本文首发于个人技术博客,转载请注明出处,本文链接:http://qifuguang.me/2015/11/11/揭秘Node-js中exports和module-exports/

如果你喜欢我的文章,请关注我的微信订阅号:“机智的程序猿”,更多精彩,尽在其中:


相关文章

  • 图文揭秘Node.js中exports和module.expor

    概述 首先我们得先摆出两条不变的真理: exports一开始是指向module.exports的; 通过requi...

  • 彻底搞懂Node.js中exports与module.expor

    先看个例子 A: b 浅拷贝了 a,可以说 b 是 a 的引用,因为它们指向了同一个内存地址,它们相互影响。但是!...

  • 六.JavaScript——exports、module.exp

    node.js中的导入导出 定义 exports——导出 module.exports——导出 require——...

  • 暴露API

    exports和module.exports 是node.js两种对外暴露的方式。 注意 exports返回的是对...

  • 模块

    一个Node.js文件就是一个模块 Node.js提供exports和require两个对象,其中 exports...

  • Node.js中exports和module.exports [

    写的很生动形象## exports和module这两个对象是所有Node.js类型的文件中都默认隐式存在的; ex...

  • Node.js

    模块Node.js 提供了exports 和 require 两个对象,其中 exports 是模块公开的接口,r...

  • node.js中的module.exports和exports

    之前对exports和module.exports一直存在疑惑,知道exports使用不当可能会导致问题,所以一直...

  • 2017-06-13今日总结

    经历: 今天看了exports和module.exports,然后尝试着写了node.js的题 还有就是看了一会数...

  • Node.js 之学习笔记

    这里有一只小白在学习Node.js,相关大神请撤离 :) module.exports和exports的区别 首先...

网友评论

  • 98a4edca2264:看下源码就知道啦,你讲的还是表面,停留在应用层面。对于require的源码,它什么时候在全局变量里加入export s和module.exports的,一目了然。
    winwill2012:@流浪的二胡 多谢指点
  • ecb8b3ab6a1e:好
    winwill2012:@tonytu 谢谢

本文标题:图文揭秘Node.js中exports和module.expor

本文链接:https://www.haomeiwen.com/subject/dwihhttx.html