module.exports属性与exports变量的区别

简介: module.exports属性与exports变量的区别

正文


一、CommonJS 模块规范


Node 应用由模块组成,采用 CommonJS 模块规范。


每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。


CommonJS 规范规定,每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(即 module.exports )是对外的接口。加载某个模块,其实是加载该模块的 module.exports 属性。


CommonJS 规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。


CommonJS 模块的特点如下:

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。


1. module.exports 属性


module.exports 属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取 module.exports 变量。


2. exports 变量


为了方便,Node 为每个模块提供一个 exports 变量,它指向 module.exports。这等同于在每个模块头部,有一行这样的命令:var exports = module.exports,我们可以通过以下方式来验证

console.log(exports === module.exports);  // true


所以在对外输出模块接口时,可以向 exports 对象添加属性方法。

module.exports.age = 20
module.exports.getAge = function() {}
// 相当于
exports.age = 20
exports.getAge = function() {}


但是不能直接将 exports 变量指向一个值,因为这样等于切断了 exportsmodule.exports 的联系。

// 以下写法无效,因为 exports 不再指向 module.exports 了。
exports = function() {};


3. module.exports 与 exports 的使用


当一个模块的对外接口,只是一个单一的值时,不能使用 exports 输出,只能使用 module.exports 输出。

// moduleA.js
// 1️⃣ 正确 ✅
module.exports = function() {};
// 2️⃣ 错误 ❎
exports = function() {};


导入模块看结果:

// other.js
var moduleA = require('moduleA.js');
console.log(moduleA);
// 两种写法打印的值分别为:
// 1️⃣ 预期结果 ✅  ƒ () { console.log('moduleD'); }
// 2️⃣ 非预期结果 ❎  {}


分析结果:


首先我们要知道 module.exports 的初始值是 {},当执行 exports = function() {}; 赋值时,无论赋值的是基本数据类型还是引用数据类型,都将改变 exports 的指向,即切断了 exportsmodule.exports 的联系。但是我们模块对外输出的接口是 module.exports,所以 2️⃣ 得到的是初始值 {}

如果你觉得 exportsmodule.exports 之间的区别很难分清,一个简单的处理方法,就是放弃使用 exports,只使用 module.exports

*我个人也没觉得 exports 的写法有多方便,哈哈。


4. 总结


非常简单,就三点:


  • module.exports 初始值为一个空对象 {}
  • exports 是指向的 module.exports 的引用;
  • require() 返回的是 module.exports 而不是 exports

还是那句话,如果你觉得 exportsmodule.exports 之间的区别很难分清,一个简单的处理方法,就是放弃使用 exports,只使用 module.exports


二、require() 扩展话题


以下案例源自知乎某帖回答,这里


关于 require() 的解释


To illustrate the behavior, imagine this hypothetical implementation of require(), which is quite similar to what is actually done by require():

function require(/* ... */) {
  const module = { exports: {} };
  ((module, exports) => {
    // Module code here. In this example, define a function.
    function someFunc() {}
    exports = someFunc;
    // At this point, exports is no longer a shortcut to module.exports, and
    // this module will still export an empty default object.
    module.exports = someFunc;
    // At this point, the module will now export someFunc, instead of the
    // default object.
  })(module, module.exports);
  return module.exports;
}


注意实现顺序,也就是下面代码为什么不成功的原因。

// moduleA.js
module.exports = function() {};
// 为什么这段配置不成功?你们有 BUG!!!
exports.abc = 'abc';


require() 的时候,是先通过 exports.abc 获取, 然后通过 module.exports 直接覆盖了原有的 exports,所以 exports.abc = 'abc' 就无效了。


一般库的封装都是 exports = module.exports = _ (underscore 的例子)。


原因很简单,通过 exports = module.exportsexports 重新指向 module.exports


三、References



The end.


目录
相关文章
|
8月前
|
JavaScript 前端开发
CMD和UMD,ES Module的差别
CMD和UMD,ES Module的差别
|
8月前
ES5、ES6类的定义
ES5和ES6都支持类的定义,但ES6引入了更简洁的语法。在ES5中,类是函数,方法绑定在原型上;而ES6使用`class`关键字,构造方法为`constructor`,方法直接定义在类内。ES6的类继承使用`extends`关键字,子类需调用`super`初始化父类属性。示例展示了Person类及其Student子类的定义和方法调用。
56 1
|
8月前
|
JavaScript 前端开发
ES6 函数
ES6(ECMAScript 2015)是 JavaScript 的一个重要版本,它引入了许多新的特性和语法。其中,函数是 ES6 的一个重要组成部分,它提供了许多新的函数语法和特性,如箭头函数、函数参数默认值、函数解构赋值等。
49 8
|
JavaScript
export default和module.exports
export default和module.exports
66 0
|
Web App开发 Dart JavaScript
剖析require、import、export、exports、module.exports以及export default 的基本用法
剖析require、import、export、exports、module.exports以及export default 的基本用法
114 0
导出与导入(require,import,module.exports,exports,export,export default)
导出与导入(require,import,module.exports,exports,export,export default)
74 0
[✔️]lua中的module函数
[✔️]lua中的module函数
254 0
Zp
|
JavaScript
Vue中的export default 和带返回值的data()以及@符号的作用
Vue中的export default 和带返回值的data()以及@符号的作用
Zp
308 0
|
JavaScript 小程序 前端开发
(区别、详解、使用)module.exports与exports,export与export default,import 与require
变量的导出涉及到四个关键字module.exports与exports,export与export default, 其中module.exports与exports是符合CommonJS模块规范的。
420 0
(区别、详解、使用)module.exports与exports,export与export default,import 与require
|
JavaScript 开发者
exports和module.exports的区别|学习笔记
快速学习 exports 和 module.exports 的区别
exports和module.exports的区别|学习笔记