Node.js模块:require实现原理、 exports与m

2018-07-28  本文已影响0人  苦苦修行

参考文献: module-模块(来自官方文档)

1. exportsmodule.exports的区别

分析一下node.js中require方法的实现原理,一切就都明白了!(所以可以跳过第一步,直接看require实现原理)

我们先将需要到的元素准备好,假设我们有两个文件:
一个是我们需要导入的模块文件,比如起名叫my-module-file.js
另一个是需要导入my-module-file.js的文件,比如起名叫index.js

这两个文件的代码比如如下所示:

/**
* my-module-file.js
*/
var one = 1;
var two = 2;
exports.a = one;
module.exports.b = two;
/**
* index.js
*/
var MyModule = require('./my-module-file.js'); // 其实 return module.exports

/*
* 输出为1
* why?上面不刚说了 require 是 return module.exports吗?
* 按道理讲不应该输出 undefined 吗?module.exports 中不是没有属性 a 吗?
* 这是因为在node.js的模块系统中,初始状态是 exports = module.exports = {}
* 所以他们共同指向同一个对象,肯定有属性 a
*/
console.log(MyModule.a);

console.log(MyModule.b); // 输出为2

改下一下再看看👀效果

/**
* my-module-file.js
*/
var one = 1;
var two = 2;
exports = { a: one };
module.exports.b = two;
/**
* index.js
*/
var MyModule = require('./my-module-file.js'); // 其实 return module.exports

/*
* 输出为 undefined
* why?怎么不是输出为 1 了?
* 这是因为 exports = module.exports = {} 这个初始状态被 exports = { a: one } 这个赋值破坏了
* 这时他们已经不再指向同一个对象了
* exports指向的是 { a: one } 这个对象,
* 而 module.exports 还是指向初始状态的那个对象,不过因为添加了属性 b,所以这个对象的看起来是 { b: two }
*/
console.log(MyModule.a); 

console.log(MyModule.b); // 输出为2

好了,先对上面说的一大堆来个小结:


2. require实现原理:

有没有想过require方法是怎样导出模块的?
require的方法实现应该看起来像是这样的:

function require(your-module){

  var module = {
    exports: {}
  };
  
  var exports = module.exports;

  (function(exports, module) {

    /**
    * 将 your-module 里你写的代码放在了这个立即执行的函数里
    * node.js是怎么将你的代码放过来的呢,应该是通过文件读取操作,将文件内容写入进来的
    * 具体文件读取操作是怎么实现的,不在本文讨论
    * 那接下来我们将 your-module 里的代码搬过来看看是什么样子的呗
    * 那我们就把 my-module-file.js 里的代码搬过来呗
    */
    var one = 1; // 知道为啥在模块文件(my-module-file.js)中定义的变量仅限在模块文件中访问了吧
    var two = 2; // 因为他们都是在“立即执行函数”里执行的,外面肯定访问不到
    exports.a = one;
    module.exports.b = two;

  })(exports, module);

  return module.exports;
}

看完上面这段代码,是不是就很清晰了。


3. 模块查找机制

require(your-module)


题外话:

require.resolve(request[, options])这个方法会解析你请求的模块,返回给你这个模块文件的实际路径

上一篇 下一篇

猜你喜欢

热点阅读