node.js中的require()如何工作?


75

我尝试了这个:

// mod.js
var a = 1;
this.b = 2;
exports.c = 3;

// test.js
var mod = require('./mod.js');
console.log(mod.a);    // undefined
console.log(mod.b);    // 2
console.log(mod.c);    // 3, so this === exports?

所以我想象require()可能是这样实现的:

var require = function (file) {
    var exports = {};
    var run = function (file) {
        // include "file" here and run
    };
    run.apply(exports, [file]);
    return exports;
}

是对的吗?请帮助我了解require()或在哪里可以找到源代码。谢谢!

Answers:


53

源代码在这里exports/require不是关键字,而是全局变量。你的主要脚本开始在其拥有所有喜欢全局的功能requireprocess等在其上下文。

请注意,虽然module.js本身正在使用require(),但这是一个不同的require函数,它是在名为“ node.js”的文件中定义

上面的副作用:在模块的中间(不属于任何函数)有“ return”语句,可以有效地“注释”其余代码,这是完全可以的


这并没有使其变得更简单。该模块require在定义的同时使用require。仅考虑到源代码,我发现这很难理解。
polkovnikov.ph 2015年

模块本身中的require是不同的需求。创建了模块的简化版本以引导模块系统-在此处查看代码-github.com/nodejs/node/blob/v4.0.0/src/node.js#L861-L949
Andrey Sidorov

这些全局变量及其返回值的文档在哪里?
斯里肯

官方文档中的@Srikan-nodejs.org/dist/latest - v8.x/ docs/ api/… (我对调用export / require全局变量并不完全正确-通常它们是包装函数(称为包装函数)的参数当您的模块加载时)
Andrey Sidorov

1
@AlexanderMills并非完全是全局变量,它来自每个模块都包装在一个函数中并require作为该函数的参数之一传递的事实
Andrey Sidorov,2016年

8

Andrey展示了源代码,但是如果您还想知道如何使用它,则在此处(http://nodejs.org/api/modules.html)进行简单的说明。

这对我来说是两个很好的例子。

//foo.js, multiple methods
var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is ' + circle.area(4));

//circle.js
var PI = Math.PI;
exports.area = function (r) {
  return PI * r * r;
};
exports.circumference = function (r) {
  return 2 * PI * r;
};

//bar.js
var square = require('./square.js');
var mySquare = square(2);
console.log('The area of my square is ' + mySquare.area());

//square.js, single method
module.exports = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

我最喜欢的模式是

(function (controller) {

  controller.init = function (app) {

    app.get("/", function (req, res) {
        res.render("index", {});
    });

  };
})(module.exports);

如果定义a var express = require('express'),为什么要在其后将另一个变量重新定义为var app = express()
TomSawyer

没得到您最喜欢的模式与需求有什么关系
ishandutta2007

@TomSawyer,因为require('express')返回一个返回应用程序的函数。这只是他们构建它的方式。希望自从4年前问这个问题以来,您已经回答了。
埃里克·杰克

6
var mod = require('./mod.js');

require是一个带有一个称为path的参数的函数,在这种情况下path为 ./mod.js

调用require时,将发生一系列任务:

  1. lib / module.js中声明的调用Module.prototype.require函数,该函数断言路径存在并且是字符串

  2. 调用Module._load,它是lib / module.js中的一个函数,它通过以下方式解析文件Module._resolveFilename(request, parent, isMain)

  3. Module._resolveFilename调用该函数并检查模块是否为本地模块(本地模块由lib / internal / bootstrap_node.js中NativeModule定义的函数返回),如果是,它将返回该模块,否则它将检查parh的字符数(必须为2字符至少)和一些字符(路径必须通过启动)通过函数定义在所定义./Module._resolveLookupPathslib / internal / bootstrap_node.js
  4. 检查包含文件的目录
  5. 如果路径包含扩展名(在我们的示例中为:mod.js),则lib / path.js中定义的basename函数将检查扩展名是否为“ js
  6. 然后它将为参数中给出的文件创建一个新模块 var module = new Module(filename, parent);
  7. 内容将通过v8中的NativeModule.prototype.compile定义的函数进行编译lib / internal / bootstrap_node.js中
  8. NativeModule.wrap中定义的lib /内部/ bootstrap_node.js需要编译的JavaScript内容mod.js并把它封装:它把它封装在其他一些代码,使所有这些工作。因此,您编写的代码mod.js将包装在函数表达式中。这意味着您在节点中编写的所有内容均在V8中运行
  9. 返回的是module.exports


-9

该资源可在下载旁边找到:http : //nodejs.org/exports/require是关键字,我认为它们不是直接用javascript编码的。Node用C ++编码,javascript只是C ++核心周围的脚本外壳。


当您只是“思考”或猜测时,最好不要回答问题。从文件系统加载和解析模块时,模块将其包装在一个函数中,并由v8引擎对其进行编译,最后对该模块进行缓存。requiremodule__filename,等都是函数和变量注入编译后的模块,并在V8引擎上下文模块运行,但模块本身是一个封闭,所以变量和函数永远不会发生冲突(除了在情况下,你使用全局变量和混乱
Jone Polvora
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.