(转)Node.js module.exports与exports

本文转自Node.js module.exports与exports
做者: chemdemojavascript

折腾Node.js有些日子了,下面将陆陆续续记录下使用Node.js的一些细节。java

熟悉Node.js的童鞋都知道,Node.js做为服务器端的javascript运行环境,它使用npm做为通用的包管理工具,npm遵循CommonJS规范定义了一套用于Node.js模块的约定,关于npm实现Node.js模块的更多细节请细读深刻Node.js的模块机制,这里简单讲下书写Node.js代码时module.exports与exorts的区别。git

在浏览器端js里面,为了解决各模块变量冲突等问题,每每借助于js的闭包把全部模块相关的代码都包装在一个匿名函数里。而Node.js编写模块至关的自由,开发者只须要关注require,exports,module等几个变量就足够,而为了保持模块的可读性,很推荐把不一样功能的代码块都写成独立模块,减小各模块耦合。开发者能够在“全局”环境下任意使用var申明变量(不用写到闭包里了),经过exports暴露接口给调用者。github

咱们常常看到相似export.xxx = yyy或者module.exports = xx这样的代码,可实际在经过require函数引入模块时会出现报错的状况,这是什么缘由致使的呢?npm

Node.js在模块编译的过程当中会对模块进行包装,最终会返回相似下面的代码:浏览器

(function (exports, require, module, __filename, __dirname) {
    // module code...
});

其中,module就是这个模块自己,require是对Node.js实现查找模块的模块Module._load实例的引用,__filename和__dirname是Node.js在查找该模块后找到的模块名称和模块绝对路径,这就是官方API里头这两个全局变量的来历。服务器

关于module.exports与exorts的区别,了解了下面几点以后应该就彻底明白:闭包

模块内部大概是这样:函数

exports = module.exports = {};
  • exports是module.exports的一个引用
  • require引用模块后,返回给调用者的是module.exports而不是exports
  • exports.xxx,至关于在导出对象上挂属性,该属性对调用模块直接可见
  • exports =至关于给exports对象从新赋值,调用模块不能访问exports对象及其属性
  • 若是此模块是一个类,就应该直接赋值module.exports,这样调用者就是一个类构造器,能够直接new实例
    客官若是看明白咋回事儿了下面的内容能够忽略:)

假若有模块a.js代码以下:工具

exports.str = 'a';
exports.fn = function() {};

对a模块的调用:

var a = require('./a');
console.log(a.str);
console.log(a.fn());

这样用是对的,若是改造a以下:

exports.str = 'a';
exports = function fn() {};

在调用a模块时天然没用fn属性了。

再改造下a模块:

exports.str = 'a';
module.exports = function fn() {};

这时a模块其实就是fn函数的引用,也就是说能够require('./a')()这样使用,而同时再也不有str属性了。

下面直接导出一个类:

module.exports = function A() {};

调用:

var A = require('./a');
var a = new A();

总结下,有两点:

  1. 对于要导出的属性,能够简单直接挂到exports对象上
  2. 对于类,为了直接使导出的内容做为类的构造器可让调用者使用new操做符建立实例对象,应该把构造函数挂到module.exports对象上,不要和导出属性值混在一块儿 最后,不用再纠结module.exports与exorts何时该用哪一个了吧~
相关文章
相关标签/搜索