如果在Express js中间件中调用函数表达式,为什么会悬挂呢?

Ast*_*nca 2 javascript node.js express

我们知道函数声明已被提升,您可以在脚本中的任何位置调用它们。函数表达式不是这种情况。

例如:

 test();

 const test = () => {
    console.log(1+3);
 }

 When we call test() it will always return undefined.
Run Code Online (Sandbox Code Playgroud)

但是,当我们在expressjs中间件中调用相同的函数时,不会发生这种情况。

router.get('/', (req, res, next) => {
   test(); // it will return always the result 4
})

const test = () => {
   console.log(1+3);
}
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释为什么会这样吗?

jfr*_*d00 5

完全按照您的说明运行时,您的第一个代码段将产生此错误:

ReferenceError: test is not defined
Run Code Online (Sandbox Code Playgroud)

您的第二个代码段有效,因为模块已初始化并const test已定义。然后过一会儿,路由回调被调用并被test定义,并在模块作用域中具有一个值。

对于letconst,在初始化它们之前在运行代码中引用它们是错误的。这就是第一个代码段生成一个的原因ReferenceError

但是,一旦初始化,它们就可以在定义它们的范围内的任何地方使用。有人将此举升到范围的顶部。因为它的工作方式不同于var吊装,所以我只是认为一旦定义了constlet符号,它就可以在其范围内的任何位置使用,即使在可能稍后调用但在文件中更早出现的代码中也是如此。这与Javascript对变量的运行时查找一致。在第二个代码片段中执行路由处理程序时,将test在其范围内动态查找该符号。由于const test已经运行并且在调用路由处理程序时已初始化,因此它会找到一个已初始化的test变量,并且test()工作正常。

在您的第一个代码段中,动态查找test失败,因为const test在您尝试调用时尚未运行test()并创建ReferenceError


您可以在此代码中看到更简单的演示,它与您的第二个片段几乎相同:

function a() {
    test();
}

const test = () => {
    console.log(1+3);
}

a();
Run Code Online (Sandbox Code Playgroud)

在这里,我们定义函数a,然后定义const test为函数。然后,我们a()依次调用test()。由于事件的顺序是:

  1. 定义功能
  2. 将const test定义为函数
  3. 呼叫 a()
  4. 然后调用 test()

并且,所有符号都可以从模块范围访问,然后您可以看到test在调用它之前已定义了这些符号,因此代码可以正常工作。