日常的学习笔记,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue全家桶,后续可能还会继续更新 Typescript、Vue3 和 常见的面试题 等等。
看过上一篇文章,我们对 require
的基本使用和其实现原理已经了解的差不多了。
通过对源码的学习,我们也会产生以下几个问题。
关于require的几个问题
首先,我们还是定义两个文件,一个导出一个引入。
// 使用 require 引入文件
// a.js
module.exports = "hello";
// b.js
let a = require('./a')
console.log(a); // hello
在上一篇源码分析的文章中,我们提到过这么一个点。
this = module.exports = exports
(具体可以参考我上一篇文章 require的实现)
那如果我们在这里输出 module.exports === exports
,结果又会如何呢?
module.exports、exports和this的关系
首先,我们先看一下上面那个问题的结果。
// a.js
console.log(module.exports === exports); // true
console.log(module.exports === this , exports === this); // true true
输出的结果是 true
,我们还可以发现这三个值互换结果都是相等的。就是因为 this = module.exports = exports
。
既然他们三个是相等的,那么我是不是就可以直接 用 exports = "hello"
来输出结果了呢?
答案是不行。原因也很简单,因为我们在定义的时候是采用 let exports = module.exports = {}
的这种定义方式进行定义,文件在引用时,返回的是 module.exports
的值。 我们给 exports
赋值为 hello ,但 module.exports
依旧是空的。
// 大概意思,具体实现可参考源码
function require(){
let exports = module.exports = {};
exports = "hello";
return module.exports;
}
我们既然知道了这种赋值方式不行是因为值引用的问题,那么我们很快就可以想到。 是否可以利用堆栈内存的特性,给他们绑定一个属性呢?
// a.js
exports.a = "hello";
this.a = "hello";
module.exports.a = "hello";
// b.js
let a = require('./a')
console.log(a.a); // hello
我们发现,这三种形式都可以进行值的传递和引用。其含义就是 定义其堆内存中地址的值, 且修改堆的值的指向。
假设我们同时定义 module.exports
和 属性,那么结果会获取 module.exports
的值,不会获取属性。
(注:不能直接修改 this
的值,可能会发生一些错误)
// a.js
module.exports.a = "hello";
module.exports = "world";
// b.js
let a = require('./a')
console.log(a); // world
因为 module.exports
的优先级是最高的,因为最终还是将 module.exports
导出。(所以 require
方法不支持多种写法同时导出)
module.exports的简化
看过上面的定义,我们可以简单整理一下 module.exports
的简化写法。
exports简化
我们现在需要将模块内的多个值导出。
// a.js
module.exports.a = "a";
module.exports.b = "b";
module.exports.c = "c";
// b.js
let result = require('./a')
console.log(); // { a: 'a', b: 'b', c: 'c' }
这样写会很麻烦,所以我们可以使用 exports
来进行简化
// a.js
exports.a = "a";
exports.b = "b";
exports.c = "c";
// b.js
// ... { a: 'a', b: 'b', c: 'c' }
就是对代码进行简化。
module.exports简化
现在有多个方法需要导出,我们就可以用下面的方式简写。
// a.js
module.exports = {
fn1(){},
fn2(){},
// ...
}
这种就是 module.exports
结合 ES6 的一种简写方式。
至此,我们的 Node的文件模块 和 Node的核心模块 就总结完毕了。
下一篇文章我会总结一下 Node中第三方模块。
本篇文章由莫小尚创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。
您也可以关注我的 个人站点、博客园 和 掘金,我会在文章产出后同步上传到这些平台上。
最后感谢您的支持!