nodejs里的module.exports和exports
引
在node.js中我们可以使用module.exports和exports导出模块,设置导出函数、数组、变量等等
为什么可以用这两个模块?
或者直接问,node.js的模块功能是怎么实现的。
这样得益于javascript是函数性的语言,并支持闭包。
js的闭包
直接看w3cschool吧,感觉讲的挺好的:js闭包
node.js的模块实现,大致代码
首先准备一个nodejs规范的代码:
hello.js
var s = 'Hello';
var name = 'world';
console.log(s + ' ' + name + '!');
Node.js加载了hello.js后,它把这段代码包装一下,大概变成这样:
var module = {
id: 'hello',
exports: {}
};
var load = function () {
// 实际我们自己编写的hello.js代码:
function greet(name) {
console.log('Hello, ' + name + '!');
}
module.exports = greet;
// hello.js代码结束
return module.exports;
};
var exports = load();
// 保存module:
save(module, exports);
module是nodejs自动加的一个对象,可见,初始化的时候会先对module.exports赋值一个空的对象{}。
save(module, exports);这个函数是个真·全局函数,作用是把exports这个变量存到某个全局变量中。其它模块通过require()函数实际上就是去这个全局变量里把对应的值拿出来。
这样,看js代码大概就明白了,为什么在nodejs里可以直接用module.exports和exports这两个语法。
module.exports和exports
module.exports和exports实际上都是对一个对象的引用,这个对象初始化就是一个空对象{}。所以直接就可以使用类似
示例一:
module.exports.foo = function () { return 'foo'; };
module.exports.bar = function () { return 'bar'; };
或者示例二:
exports.foo = function () { return 'foo'; };
exports.bar = function () { return 'bar'; };
这两个示例作用是一样的,其本质都是往最开始初始化的空数组里添加成员。
示例三
module.exports = {
hello: hello,
greet: greet
};
示例三就不一样了,实际上module.exports重新引用到了一个新的对象里。如果示例三前面有示例一或者二的代码,那么会最终导致示例一或者二导出的模块丢掉。
示例四
exports = {
hello: hello,
greet: greet
};
示例四看上去虽然和示例三差不多,但是这种写法实际上并没有输出任何变量!注意看nodejs的实现代码,load()函数里最后return的是module.exports,也就是说最后save的是module.exports的引用对象,而示例四中exports被赋值了一个新的对象,此时module.exports和exports引用的已经不是同一个对象了!
那么提问:示例三虽然对module.exports重新引用到了一个新的对象,最终结果也能实现模块的正常导出,那么示例三里的exports此时引用的是什么对象呢?
最后,如果你打算导出一个数组或者变量,或者函数,都会涉及到module.exports原引用对象的丢弃,要额外注意,此时要小心不要丢掉前面已经导出的模块。
结论
如果要输出一个键值对象{},可以利用exports这个已存在的空对象{},并继续在上面添加新的键值;
如果要输出一个函数或数组,必须直接对module.exports对象赋值。
所以我们可以得出结论:直接对module.exports赋值,可以应对任何情况:
module.exports = {
foo: function () { return 'foo'; }
};
或者:
module.exports = function () { return 'foo'; };
最终,我们强烈建议使用module.exports = xxx的方式来输出模块变量,这样,你只需要记忆一种方法。
或者使用我喜欢的方法,对空对象直接添加值:
var foo = function () { return 'foo'; };
...
module.exports.foo = foo;//
module.exports.bar = function () { return 'bar'; };
参考
JS是按值传递还是按引用传递?,但是我不是很同意文中所说的按共享传递这名字的叫法。实际上无论传递普通变量还是传递函数,都是按值拷贝传递,只不过传递对象的时候,拷贝过去的是个引用变量罢了,即引用副本。
这里就是c语言指针的思想。
如果你对我上面所讲的还不明白,建议去把c语言里的指针好好的重学一遍。真正理解透彻了c里面的指针,学起来其它所有语言都不怕。
nodejs里的module.exports和exports的更多相关文章
- nodejs里的module.exports和exports的关系
关于node里面的module.exports和exports的异同,网上已经有很多的资料,很多的文章,很多的博客,看了很多,好像懂了,又好像不懂,过几天又不懂了...大致总结是这样的: //下面这种 ...
- node (02 CommonJs 和 Nodejs 中自定义模块)顺便讲讲module.exports和exports的区别 dependencies 与 devDependencies 之间的区别
CommonJS 规范的提出,主要是为了弥补当前 JavaScript 没有标准的缺陷.它的终极目标就是:提供一个类似 Python,Ruby 和 Java 语言的标准库,而不只是停留在小脚本程序的阶 ...
- 关于common.js里面的module.exports与es6的export default的思考总结
背景 公司项目需要裁切功能,基于第三方图片裁切组件vue-cropper(0.4.0版本),封装了图片裁切组件(picture-cut)(放在公司内部组件库,仅限于公司内部使用) 在vue-cropp ...
- module.exports 与 exports
module.exports 与 exports 注意:1 对于要导出的属性,可以简单直接挂到 exports 对象上2 对于类,为了直接使导出的内容作为类的构造器可以让调用者使用 new 操作符创建 ...
- module.exports和exports得区别
对module.exports和exports的一些理解 可能是有史以来最简单通俗易懂的有关Module.exports和exports区别的文章了. exports = module.exports ...
- (转)Node.js module.exports与exports
本文转自Node.js module.exports与exports 作者: chemdemo 折腾Node.js有些日子了,下面将陆陆续续记录下使用Node.js的一些细节. 熟悉Node.js的童 ...
- module.exports和exports
require 用来加载代码,而 exports 和 module.exports 则用来导出代码.但很多新手可能会迷惑于 exports 和 module.exports 的区别,为了更好的理解 e ...
- Module.exports和exports的区别
原文链接: https://www.ycjcl.cc/2017/02/10/module-exportshe-exportsde-qu-bie/ 学习Seajs时,看到了exports.doSomet ...
- module.exports,exports和export default,export的区别
前提:CommonJS模块规范和ES6模块规范是完全不同的两个概念. module.exports,exports属于CommonJS模块规范: export default,export属于ES6模 ...
随机推荐
- 201521123117 《Java程序设计》第2周学习总结
本周学习总结: 1.String常量,创建之后不能再进行修改 2.类管理机制是包. 3.Java数组的使用. 书面作业: Q1:使用Eclipse关联jdk源代码,并查看String对象的源代码(截图 ...
- 201521123072《java程序设计》第十一周学习总结
201521123072<java程序设计>第十一周学习总结 1. 本周学习总结 2. 书面作业 本次PTA作业题集多线程 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问 ...
- 201521123036 《Java程序设计》第10周学习总结
本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 书面作业 本次PTA作业题集异常.多线程 finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 ...
- 201521123035《Java程序设计》第十二周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int age,doubl ...
- 201521123052《Java程序设计》第10周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题集异常.多线程 1.finally 题目4-2 1.1 截图你的提交结果(出 ...
- java:java构造器和java方法的区别
构造函数(构造器)是一种特殊的函数.其主要功能是用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.构造函数与类名相同,可重载多个不同的构造函数.在JA ...
- 搭建连接MySql的三层架构的ASP.NetCore2.0的WebApi
里我们用三层架构搭建一个连接MySql的ASP.netCore模板的WebApi项目 首先添加WebApi项目(ASP.NetCore版本) 右键解决方案>新建项目> 选择Web>A ...
- 读Zepto源码之Touch模块
大家都知道,因为历史原因,移动端上的点击事件会有 300ms 左右的延迟,Zepto 的 touch 模块解决的就是移动端点击延迟的问题,同时也提供了滑动的 swipe 事件. 读 Zepto 源码系 ...
- IDEA 2 的注册码
43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...
- 将数组分割为几个等长度的子数组(使用slice)
先了解一下slice方法: slice() 1.定义:slice()可从已有数组中截取返回指定的元素,形成一个新的数组: 语法:arrayObject.slice(start,end): 参数 描述 ...