手写Node模块系统-面试题底层原理

NodeJS 中的 this 为什么是一个空对象:

因为所有的 NodeJS 文件在执行的时候都会被包裹到一个函数中,this 都被修改为了空的 module.exports

(function (exports, require, module, __filename, __dirname) {
    // 我们编写的代码
	// 所以说在这里面拿到的 this 就是空的 module.exports
});

compiledWrapper.call(module.exports, args);

image-20210821094554649

NodeJS 中为什么可以直接使用 exportsrequiremodule__filename__dirname

因为所有的 NodeJS 文件在执行的时候都会被包裹到一个函数中,这些属性都被通过参数的形式传递过来了

var args = [module.exports, require, module, filename, dirname];

compiledWrapper.call(this.exports, args);

image-20210821094908926

NodeJS 中为什么不能直接 exports 赋值,而可以给 module.exports 赋值,如果直接给 exports 赋值拿到的是一个空对象如下:

image-20210821095438643

image-20210821095449229

如果不是直接赋值运行就能拿到暴露的数据如下:

image-20210821095752759

image-20210821095809078

先来看直接赋值暴露数据内存示例图以及所对应的代码:

image-20210821213743383

对应的代码如下:

image-20210821214108542

image-20210821214122969

直接赋值的最终执行的代码如下,改变了 exports 的指向:

(function (exports, require, module, __filename, __dirname) {
    exports = "BNTang";
});

jsScript.call(module.exports, module.exports);
return module.exports;

相当于如下代码:

let exports = module.exports;

exports = "BNTang";

return module.exports;

image-20210821215009480

直接赋值改变了形参当中 exports 所指向的对象,指向了 "BNTang",所以拿到的是一个空对象在来看看不是直接赋值的内存示例图:

image-20210821214144127

内部的代码如下:

(function (exports, require, module, __filename, __dirname) {
    exports.name = "BNTang";
});

jsScript.call(module.exports, module.exports);
return module.exports;

因为形参当中的 exports 所指向的对象和 module.exports 是同一个所以拿到的不是空对象

通过 require 导入包的时候应该使用 var / let 还是 const

导入包的目的是使用包而不是修改包,所以导入包时使用 const 接收

posted @ 2021-08-21 10:07  BNTang  阅读(53)  评论(0编辑  收藏  举报