英文:
CommonJS Require Mechanics
问题
根据我的教材,require
函数的定义如下:
require.cache = Object.create(null);
function require(name) {
if (!(name in require.cache)) {
let code = readFile(name);
let module = {exports: {}};
require.cache[name] = module;
let wrapper = Function("require, exports, module", code);
wrapper(require, module.exports, module);
}
return require.cache[name].exports;
}
注意事项:
readFile(name)
是一个取决于是否使用 Node.js 或特定浏览器的任意函数。- 我们将缓存设置为空对象。
- 这是我的教材引用的代码摘录。
为了避免多次加载相同的模块,require
会保持一个已加载模块的存储(缓存)。当调用时,它首先检查所请求的模块是否已加载,如果没有,则加载它。这涉及读取模块的代码,将其包装在函数中,并调用它。
关于您不理解的部分:
在这种情况下,递归是如何工作的呢?我真的很困惑包装函数。
英文:
According to my textbook, the definition of the require function is this
require.cache = Object.create(null);
function require(name) {
if (!(name in require.cache)) {
let code = readFile(name);
let module = {exports: {}};
require.cache[name] = module;
let wrapper = Function("require, exports, module", code);
wrapper(require, module.exports, module);
}
return require.cache[name].exports;
}
Notes:
readFile(name)
is an arbitrary function that depends on whether I am using node.js or a particular browser.- We set the cache to be an empty object
- This is what my textbook quoted about the code.
> To avoid loading the same module multiple times, require keeps a store
> (cache) of already loaded modules. When called, it first checks if the
> requested module has been loaded and, if not, loads it. This involves
> reading the module’s code, wrapping it in a function, and calling it.
What I do not understand:
How does the recursion work in this case. I am just really confused about the wrapper function.
答案1
得分: 1
请找到以下已翻译的部分:
假设您有这些非常简单的模块<sup>1</sup>:
// In square.js
const square = function (n) {
return n * n;
}
module .exports = square
和
// In squareAll.js
const square = require ('./square')
const squareAll = function (ns) {
return ns .map (n => square (n))
}
module .exports = squareAll
与此主模块:
const squareAll = require ('./squareAll')
console .log (squareAll ([1, 2, 3, 4, 5]))
在外部的 require ('./squareAll')
上,当我们到达以下行时:
let wrapper = Function("require, exports, module", code);
我们创建了一个新的函数,看起来像这样:
const wrapper = function (require, exports, module) {
const square = require ('./square')
const squareAll = function (ns) {
return ns .map (n => square (n))
}
module .exports = squareAll
}
我们调用这个构造函数,传递我们的 require
函数、我们的 module
对象和它的 exports
属性。然后,当其第一行被调用时,将递归调用 require
:
const square = require ('./square')
这将再次使用函数构造函数,调用那个函数,然后将 square
函数返回,并将其分配给 square
变量。回到外部调用,我们将使用 square
函数来定义 squareAll
,将其分配给 module.exports
,然后使用以下方式返回它:
return require.cache[name].exports;
我们的 index.js
函数现在具有对 squareAll
的引用,它具有对 square
的引用。由于缓存的存在,下次我们 require
其中一个时,将返回已加载的版本。
这是一个相当优雅的过程。
<sup><sup>1</sup>是的,这些可以使用箭头函数更简单地编写。我这样做是为了使尽可能多的人能够理解。</sup>
英文:
Imagine you had these extremely simple modules<sup>1</sup>:
// In square.js
const square = function (n) {
return n * n;
}
module .exports = square
and
// In squareAll.js
const square = require ('./square')
const squareAll = function (ns) {
return ns .map (n => square (n))
}
module .exports = squareAll
with this main module:
const squareAll = require ('./squareAll')
console .log (squareAll ([1, 2, 3, 4, 5]))
On that outer require ('./squareAll')
, when we get to the line
let wrapper = Function("require, exports, module", code);
we create a new Function that looks something like this:
const wrapper = function (require, exports, module) {
const square = require ('./square')
const squareAll = function (ns) {
return ns .map (n => square (n))
}
module .exports = squareAll
}
We call this constructed function passing our require
function, our module
object and its exports
property. That will then recursively call require
when its first line is called:
const square = require ('./square')
and that will use the Function constructor again, invoke that function, and will return the square
function, assigning it to the square
variable. Back in the outer call, we will use the square
function to define squareAll
, assign that to module.exports
, and then we will return it with:
return require.cache[name].exports;
Our index.js
function now has a reference to squareAll
, which has a reference to square
. And because of the caching, the next time we require
one of them, we will return the already-loaded version.
It's a fairly elegant process.
<sup><sup>1</sup>Yes, these can be written more simply with arrow function. I do, but wanted to make this understandable to as many as possible.</sup>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论