{"action":"created","issue":{"url":"https://api.github.com/repos/chemdemo/chemdemo.github.io/issues/2","repository_url":"https://api.github.com/repos/chemdemo/chemdemo.github.io","labels_url":"https://api.github.com/repos/chemdemo/chemdemo.github.io/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/chemdemo/chemdemo.github.io/issues/2/comments","events_url":"https://api.github.com/repos/chemdemo/chemdemo.github.io/issues/2/events","html_url":"https://github.com/chemdemo/chemdemo.github.io/issues/2","id":32760081,"number":2,"title":"Node.js module.exports与exports","user":{"login":"chemdemo","id":1014734,"avatar_url":"https://avatars.githubusercontent.com/u/1014734?v=3","gravatar_id":"","url":"https://api.github.com/users/chemdemo","html_url":"https://github.com/chemdemo","followers_url":"https://api.github.com/users/chemdemo/followers","following_url":"https://api.github.com/users/chemdemo/following{/other_user}","gists_url":"https://api.github.com/users/chemdemo/gists{/gist_id}","starred_url":"https://api.github.com/users/chemdemo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chemdemo/subscriptions","organizations_url":"https://api.github.com/users/chemdemo/orgs","repos_url":"https://api.github.com/users/chemdemo/repos","events_url":"https://api.github.com/users/chemdemo/events{/privacy}","received_events_url":"https://api.github.com/users/chemdemo/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2014-05-04T02:54:19Z","updated_at":"2017-01-09T06:18:17Z","closed_at":null,"body":"_折腾Node.js有些日子了，下面将陆陆续续记录下使用Node.js的一些细节。_\n\n熟悉Node.js的童鞋都知道，Node.js作为服务器端的javascript运行环境，它使用npm作为通用的包管理工具，npm遵循CommonJS规范定义了一套用于Node.js模块的约定，关于npm实现Node.js模块的更多细节请细读 @朴灵 的[深入Node.js的模块机制](http://www.infoq.com/cn/articles/Node.js-module-mechanism)，这里简单讲下书写Node.js代码时`module.exports`与`exorts`的区别。\n\n在浏览器端js里面，为了解决各模块变量冲突等问题，往往借助于js的闭包把所有模块相关的代码都包装在一个匿名函数里。而Node.js编写模块相当的自由，开发者只需要关注`require`，`exports`，`module`等几个变量就足够，而为了保持模块的可读性，很推荐把不同功能的代码块都写成独立模块，减少各模块耦合。开发者可以在“全局”环境下任意使用`var`申明变量（不用写到闭包里了），通过`exports`暴露接口给调用者。\n\n我们经常看到类似`export.xxx = yyy`或者`module.exports = xx`这样的代码，可实际在通过`require`函数引入模块时会出现报错的情况，这是什么原因导致的呢？\n\nNode.js在模块编译的过程中会对模块进行包装，最终会返回类似下面的代码：\n\n``` javascript\n(function (exports, require, module, __filename, __dirname) {\n    // module code...\n});\n```\n\n其中，`module`就是这个模块本身，`require`是对Node.js实现查找模块的模块`Module._load`实例的引用，`__filename`和`__dirname`是Node.js在查找该模块后找到的模块名称和模块绝对路径，这就是官方API里头这两个全局变量的来历。\n\n关于module.exports与exorts的区别，了解了下面几点之后应该就完全明白：\n\n模块内部大概是这样：\n\n``` javascript\nexports = module.exports = {};\n```\n- exports是module.exports的一个引用\n- require引用模块后，返回给调用者的是module.exports而不是exports\n- `exports.xxx`，相当于在导出对象上挂属性，该属性对调用模块直接可见\n- `exports =`相当于给exports对象重新赋值，调用模块不能访问exports对象及其属性\n- 如果此模块是一个类，就应该直接赋值`module.exports`，这样调用者就是一个类构造器，可以直接new实例\n\n客官如果看明白咋回事儿了下面的内容可以忽略：）\n\n假如有模块a.js代码如下：\n\n``` javascript\nexports.str = 'a';\nexports.fn = function() {};\n```\n\n对a模块的调用：\n\n``` javascript\nvar a = require('./a');\nconsole.log(a.str);\nconsole.log(a.fn());\n```\n\n这样用是对的，如果改造a如下：\n\n``` javascript\nexports.str = 'a';\nexports = function fn() {};\n```\n\n在调用a模块时自然没用`fn`属性了。\n\n再改造下a模块：\n\n``` javascript\nexports.str = 'a';\nmodule.exports = function fn() {};\n```\n\n这时a模块其实就是fn函数的引用，也就是说可以`require('./a')()`这样使用，而同时不再有str属性了。\n\n下面直接导出一个类：\n\n``` javascript\nmodule.exports = function A() {};\n```\n\n调用：\n\n``` javascript\nvar A = require('./a');\nvar a = new A();\n```\n\n总结下，有两点：\n1. 对于要导出的属性，可以简单直接挂到`exports`对象上\n2. 对于类，为了直接使导出的内容作为类的构造器可以让调用者使用new操作符创建实例对象，应该把构造函数挂到`module.exports`对象上，不要和导出属性值混在一起\n\n最后，不用再纠结`module.exports`与`exorts`什么时候该用哪个了吧～\n"},"comment":{"url":"https://api.github.com/repos/chemdemo/chemdemo.github.io/issues/comments/271217026","html_url":"https://github.com/chemdemo/chemdemo.github.io/issues/2#issuecomment-271217026","issue_url":"https://api.github.com/repos/chemdemo/chemdemo.github.io/issues/2","id":271217026,"user":{"login":"yyscamper","id":511378,"avatar_url":"https://avatars.githubusercontent.com/u/511378?v=3","gravatar_id":"","url":"https://api.github.com/users/yyscamper","html_url":"https://github.com/yyscamper","followers_url":"https://api.github.com/users/yyscamper/followers","following_url":"https://api.github.com/users/yyscamper/following{/other_user}","gists_url":"https://api.github.com/users/yyscamper/gists{/gist_id}","starred_url":"https://api.github.com/users/yyscamper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yyscamper/subscriptions","organizations_url":"https://api.github.com/users/yyscamper/orgs","repos_url":"https://api.github.com/users/yyscamper/repos","events_url":"https://api.github.com/users/yyscamper/events{/privacy}","received_events_url":"https://api.github.com/users/yyscamper/received_events","type":"User","site_admin":false},"created_at":"2017-01-09T06:18:17Z","updated_at":"2017-01-09T06:18:17Z","body":":+1: "}}
{"actor":{"display_login":"yyscamper"}}