在Node中,每个文件模块都是一个对象,它的定义如下:

function Module(id, parent) {    this.id = id;  this.exports = {}; this.parent = parent;  if (parent && parent.children) {    parent.children.push(this); }   this.filename = null;  this.loaded = false;   this.children = [];
}

编译和执行是引入文件模块的最后一个阶段。定位到具体的文件后,Node会新建一个模块对象,然后根据路径载入并编译。对于不同的文件扩展名,其载入方法也有所不同,具体如下所示。

.js 文件。通过 fs 模块同步读取文件后编译执行。 .node 文件。这是用C/C++编写的扩展文件,通过 dlopen() 方法加载最后编译生成 的文件。 .json 文件。通过 fs 模块同步读取文件后,用 JSON.parse() 解析返回结果。其余扩展名文件。它们都被当做.js文件载入。

每一个编译成功的模块都会将其文件路径作为索引缓存在 Module._cache 对象上,以提高二次引入的性能。

根据不同的文件扩展名,Node会调用不同的读取方式,如.json文件的调用如下:

Module._extensions['.json'] = function(module, filename) { var content = NativeModule.require('fs').readFileSync(filename, 'utf8');   try {   module.exports = JSON.parse(stripBOM(content));    } catch (err) { err.message = filename + ': ' + err.message;   throw err;  }
};

在确定文件的扩展名之后,Node将调用具体的编译方式来将文件执行后返回给调用者。

回到CommonJS模块规范,我们知道每个模块文件中存在着 require 、 exports 、 module 这3个变量,但是它们在模块文件中并没有定义,那么从何而来呢?

甚至在Node的API文档中,我们知道每个模块中还有 __filename 、 __dirname 这两个变量的存在,它们又是从何而来的呢?

事实上,在编译的过程中,Node对获取的JavaScript文件内容进行了头尾包装。在头部添加了 (function (exports, require, module, __filename, __dirname) {\n ,在尾部添加了 \n}); 。一个正常的JavaScript文件会被包装成如下的样子:

(function (exports, require, module, __filename, __dirname) {   var math = require('math');  exports.area = function (radius) { return Math.PI * radius * radius;   };
});

这样每个模块文件之间都进行了作用域隔离。包装之后的代码会通过 vm 原生模块的 runInThisContext() 方法执行(类似 eval ,只是具有明确上下文,不污染全局),返回一个具体的 function 对象。

最后,将当前模块对象的 exports 属性、 require() 方法、 module (模块对象自身),以及在文件定位中得到的完整文件路径和文件目录作为参数传递给这个 function() 执行。

这就是这些变量并没有定义在每个模块文件中却存在的原因。在执行之后,模块的 exports 属性被返回给了调用方。 exports 属性上的任何方法和属性都可以被外部调用到,但是模块中的其余 变量或属性则不可直接被调用。

至此, require 、 exports 、 module 的流程已经完整,这就是Node对CommonJS模块规范的实现。

const path = require('path');
const fs = require('fs');
const vm = require('vm');    function Module(id) {   this.id = id;  this.exports = {}; this.loaded = false;   this.filename = null;
}   Module._cache = Object.create(null);
Module._extensions = Object.create(null);  Module.wrap = function (script) {  return Module.wrapper[0] + script + Module.wrapper[1];
};  Module.wrapper = [ '(function (exports, require, module, __filename, __dirname) { ', '\n});'
];  Module._load = function (request) {    var filename = Module._resolveFilename(request);   var cachedModule = Module._cache[filename];    if (cachedModule) { return cachedModule.exports;    }   var module = new Module(filename); Module._cache[filename] = module;  tryModuleLoad(module, filename);    return module.exports;
};  Module._resolveFilename = function (request) { var filename = Module._findPath(request);  if (!filename) {    var err = new Error(`Cannot find module '${request}'`);    err.code = 'MODULE_NOT_FOUND';   throw err;  }   return filename;
};  Module._findPath = function (request) {    var filename = path.resolve(request);  return filename;
};  function tryModuleLoad(module, filename) {  var threw = true;  try {   module.load(filename);  threw = false; } finally { if (threw) {    delete Module._cache[filename]; }   }
}   Module.prototype.load = function (filename) {  this.filename = filename;  var extension = path.extname(filename) || '.js'; if (!Module._extensions[extension]) extension = '.js';   Module._extensions[extension](this, filename);  this.loaded = true;
};  Module._extensions['.js'] = function (module, filename) {    var content = fs.readFileSync(filename, 'utf8'); module._compile(content, filename);
};  Module._extensions['.json'] = function (module, filename) {  var content = fs.readFileSync(filename, 'utf8'); try {   module.exports = JSON.parse(content);  } catch (err) { err.message = filename + ': ' + err.message;   throw err;  }
};  Module.prototype._compile = function (content, filename) { var wrapper = Module.wrap(content);    var compiledWrapper = vm.runInThisContext(wrapper);    var dirname = path.dirname(filename);  var result; result = compiledWrapper.call(this.exports, this.exports, require, this, filename, dirname);   return result;
};  function require2(path) {   return Module._load(path);
}   let str = require2('./b.json') // 导入JSON数据

Node对CommonJS模块的实现相关推荐

  1. Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL

    文章目录 Node.js b站教学视频汇总笔记(完)CommonJS模块规范. require.npm.Express(中间件).MongoDB.MySQL 1. Node介绍 为什么要学习Node. ...

  2. Node.js 官网入门教程(一) CommonJS 模块规范、Node.js REPL、console、CLI、exports

    Node.js 官网入门教程(一) CommonJS 模块规范.Node.js REPL.console.CLI.exports 文章目录 Node.js 官网入门教程(一) CommonJS 模块规 ...

  3. CommonJs模块规范

    1.什么是模块化 文件作用域 通信规则 加载 require 导出 exports 2.CommonJs模块规范 在Node中的Javascript还有一个很重要的概念:模块概念 模块作用域 使用re ...

  4. es6 混合commjs_详谈commonjs模块与es6模块的区别

    到目前为止,已经实习了3个月的时间了.最近在面试,在面试题里面有题目涉及到模块循环加载的知识.趁着这个机会,将commonjs模块与es6模块之间一些重要的的区别做个总结.语法上有什么区别就不具体说了 ...

  5. 第二章. node中的模块和require

    2019独角兽企业重金招聘Python工程师标准>>> 一 什么是模块. JavaScript诞生初,它只不过是一个网页的小脚本而已,没有人会想到它会发展到现在能有大量的库,工具,组 ...

  6. Node 入门及模块系统

    初识Node.js与模块 ◆ 能够知道什么是 Node.js ◆ 能够知道 Node.js 可以做什么 ◆ 能够说出 Node.js 中的 JavaScript 的组成部分 ◆ 能够使用 fs 模块读 ...

  7. node篇 CommonJS规范

    文章目录 1. 每个文件就是一个模块,有自己的作用域.在一个文件里面定义的变量.函数.类,都是私有的,对其他文件不可见. 2. 每个模块内部,module变量代表当前模块. 3. 两种导出方式 exp ...

  8. JavaScript CommonJS 模块

    JavaScript CommonJS 模块是一种使用 JavaScript 语言实现的模块化编程规范.它是在服务器端开发 Node.js 应用程序时使用最广泛的模块化方案之一. CommonJS 模 ...

  9. 浏览器加载 CommonJS 模块的原理与实现

    转载:http://www.ruanyifeng.com/blog/2015/05/commonjs-in-browser.html 就在这个周末,npm 超过了cpan ,成为地球上最大的软件模块仓 ...

最新文章

  1. python 网页上显示数据_用Python实现网页数据抓取
  2. 不用python编程,制作词云图
  3. 12306的变态验证码算得了什么?我有Python神器!
  4. 第 6 期 Arthas 征文活动开启!(内附第 5 期获奖名单)
  5. 简明 ASP.NET Core 手册
  6. 使用with 创建视图
  7. 第四章 自上而下分析
  8. win7系统两台电脑之间利用Socket实现文件传输---C++实现
  9. make install到指定安装目录
  10. SourceOffSite
  11. PHP 微信公众号消息加解密
  12. 充电器pps功能是什么_科普:PPS充电器是什么?为何不兼容笔电?
  13. [读史思考] 魏王真的被张仪忽悠瘸了吗?
  14. A. K-divisible Sum
  15. html word页面展示,word文档怎样调页面
  16. 推荐系统8——利用社交网络数据推荐
  17. 药监局,药品监督管理局
  18. 创业者如何克服困难,控制焦虑情绪,走向成功
  19. android 调用下载,使用Android系统提供的DownloadManager来下载文件
  20. java 航班_Java实现简单航班查询系统-Go语言中文社区

热门文章

  1. 关于“时间序列回归”,这些你必须知道的事!
  2. Java变量声明在循环体内还是循环体外,你用哪一个?
  3. 5行Python代码实现刷爆全网的动态条形图!
  4. 马斯克火箭 SpaceX-API、程序员优雅赚钱项目……GitHub 热点速览
  5. 36000+开发者,一周投稿超 23000 篇,谁能笑傲群雄?| 第4周周榜揭晓
  6. 拿来就能用!几步搭建一套简单直播系统 | 原力计划
  7. 小米冲击高端,这次能否成功?
  8. 免费 | 开源操作系统年度盛会最新日程曝光,邀您一同开启烧脑模式!
  9. 如何在 40 秒内创建一个.Net Core Web API?
  10. 国际顶级学界和工业界大咖云集、AIoT 实训营,你不可错过的嵌入式 AI 盛会!...