当前位置: 首页 > 面试题库 >

为什么模块级return语句在Node.js中起作用?

周昊乾
2023-03-14
问题内容

当我回答另一个问题时我遇到了一个带有顶层return语句的Node.js模块。例如:

console.log("Trying to reach");
return;
console.log("dead code");

这可以正常工作并且没有错误并可以打印:

Trying to reach

在标准输出中,但不是“ dead code”- return实际停止执行。

但是根据ECMAScript
5.1中
return语句规范,

语义学

如果ECMAScript程序 包含不在内的return语句,则在语法上FunctionBody_被视为 _不正确

在上面显示的程序中return没有任何功能。

那为什么不扔呢?


问题答案:

TL; DR

Node.js将模块包装在一个函数中,如下所示:

(function (exports, require, module, __filename, __dirname) {
    // our actual module code
});

所以上面显示的代码实际上是由Node.js执行的,就像这样

(function (exports, require, module, __filename, __dirname) {
    console.log("Trying to reach");
    return;
    console.log("dead code");
});

这就是程序仅打印Trying to reach并跳过console.log以下return语句的原因。

这是我们需要了解Node.js如何处理模块的地方。当您使用Node.js运行.js文件时,它将文件视为一个模块,并使用v8
JavaScript引擎对其进行编译。

它与所有启动runMain功能,

// bootstrap main module.
Module.runMain = function() {
  // Load the main module--the command line argument.
  Module._load(process.argv[1], null, true);
  // Handle any nextTicks added in the first tick of the program
  process._tickCallback();
};

在该Module._load函数中,将创建一个新的Module对象并进行加载。

var module = new Module(filename, parent);
...
...
try {
  module.load(filename);
  hadException = false;

Module功能load做到这一点,

// Given a file name, pass it to the proper extension handler.
Module.prototype.load = function(filename) {
  debug('load ' + JSON.stringify(filename) +
        ' for module ' + JSON.stringify(this.id));

  assert(!this.loaded);
  this.filename = filename;
  this.paths = Module._nodeModulePaths(path.dirname(filename));

  var extension = path.extname(filename) || '.js';
  if (!Module._extensions[extension]) extension = '.js';
  Module._extensions[extension](this, filename);
  this.loaded = true;
};

由于文件的扩展名是js,因此我们可以看到Module._extensions它的作用.js。可以在这里看到

// Native extension for .js
Module._extensions['.js'] = function(module, filename) {
  var content = fs.readFileSync(filename, 'utf8');
  module._compile(stripBOM(content), filename);
};

module物体_compile在该函数调用,这就是魔法发生,

// Run the file contents in the correct scope or sandbox. Expose
// the correct helper variables (require, module, exports) to
// the file.
// Returns exception, if any.

这是require我们的节点模块使用的函数首先创建的地方。

function require(path) {
  return self.require(path);
}

require.resolve = function(request) {
  return Module._resolveFilename(request, self);
};

Object.defineProperty(require, 'paths', { get: function() {
  throw new Error('require.paths is removed. Use ' +
                  'node_modules folders, or the NODE_PATH ' +
                  'environment variable instead.');
}});

require.main = process.mainModule;

// Enable support to add extra extension types
require.extensions = Module._extensions;
require.registerExtension = function() {
  throw new Error('require.registerExtension() removed. Use ' +
                  'require.extensions instead.');
};

require.cache = Module._cache;

然后是包装代码的一些事情,

// create wrapper function
var wrapper = Module.wrap(content);

我们着手寻找能做什么Module.wrap,那不过是什么

Module.wrap = NativeModule.wrap;

src/node.js文件中定义的,这就是我们在其中找到的位置,

NativeModule.wrap = function(script) {
  return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
};

NativeModule.wrapper = [
  '(function (exports, require, module, __filename, __dirname) { ',
  '\n});'
];

这是我们的程序是如何有机会获得神奇的变量,exportsrequiremodule__filename__dirname

然后包装的功能是编译和执行在这里用runInThisContext

var compiledWrapper = runInThisContext(wrapper, { filename: filename });

然后终于,模块的编译包装的函数对象调用像这样,以填充值exportsrequiremodule__filename__dirname

var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);

这就是Node.js处理和执行我们的模块的方式,这就是为什么该return语句可以正常运行的原因。



 类似资料:
  • 例如: 由于指的是“nothing is return”,那么我们在这里如何使用return语句。这是否意味着所有程序都返回一些东西,不管它是void还是其他返回类型? 我还有一个关于作为返回类型的查询:

  • 问题内容: 考虑以下JavaScript: 上面的代码片段中的方法返回的是正确的值,在这种情况下。但是,该方法返回。大多数其他语言不是这种情况。 但是,以下函数是正确的,并返回正确的值。 如果语法错误,它应该发出一些编译器错误,但不会。为什么会这样? 问题答案: 从技术上讲,JavaScript中的半冒号是可选的。但是实际上 , 如果它认为缺少某些换行符, 它只会为您插入它们 。但是它为您带来的决

  • 问题内容: 我期望值可以交换。但是它给出x = 0和y = 1。当我尝试使用C语言时,它会给出正确的结果。 问题答案: 您的陈述大致相当于这种扩展形式: 与C语言不同,在Java中,保证二进制运算符的左操作数在右操作数之前进行求值。评估如下: 您可以反转每个xor表达式的参数顺序,以便在再次评估变量之前完成赋值: 这是一个更紧凑的版本,也可以使用: 但这是交换两个变量的真正可怕的方法。使用临时变量

  • 问题内容: 我是Java的新手,正在尝试学习速记语句的概念。 我想出了下面的代码。但是,该代码将无法编译,并在(即?:)语句旁边显示错误。 有人可以告诉我为什么它不起作用吗? 对不起,如果我的问题对某些人听起来很愚蠢。我是Java新手。 在此先感谢您的帮助! 问题答案: 三元表达 是一个 表达式 ,而不是一个语句,因此不能在需要语句的地方使用。 您可以这样写: 因为这是一个声明。

  • 我还检查了调试,它将语句=>if(sum==1)返回true;但它也在执行更多的语句。

  • 问题内容: 我是Java的新手,这是什么意思?像吗? 如果第二个返回true,将不会执行,对吗? 问题答案: Return语句跳过功能范围的其余执行。 值得读: :http : //docs.oracle.com/javase/tutorial/java/javaOO/returnvalue.html :http : //docs.oracle.com/javase/tutorial/java/n