3

在 JavaScript 中,当使用函数表达式(例如var myFunc = function() {...})时,就像任何其他变量声明一样,您必须在使用之前定义变量。例如,以下示例将不起作用(将导致Uncaught TypeError: myFunc is not a function):

var myVar = myFunc();

var myFunc = function() {
    // code here...
}

但是,在我的 node js 项目的 routes/index.js 文件中,我有以下代码(明显缩写):

var router = express.Router();
.
.
.
router.post('/', function(req, res) {
    ...
    ...
    var myVar = myFunc(); // WORKS!
    ...
    ...
}

var myFunc = function() {
    ...
}

myFunc变量是在使用声明的,所以这不应该抛出错误吗?

4

1 回答 1

3

这有两个方面:

  1. 当代码中的变量声明在它下面时,为什么可以通过回调来router.post访问变量?myFunc

  2. 为什么回调传递给router.post访问分配给myFunc变量的函数,当它没有分配给变量时,直到它在代码中的下方?

首先我们将处理变量,然后我们将处理它的值(我们分配给它的函数):

myFunc 变量是在使用后声明的,所以这不应该抛出错误吗?

要是var不吊起来就好了。而是var被吊起来了。因此,当您的模块被加载时, JavaScript 引擎首先会查看它以查找所有变量声明和函数声明,处理它们,然后在您的模块中执行分步代码。

例如,对于 JavaScript 引擎,您的模块实际上如下所示:

var router = undefined;
var myFunc = undefined;

router = express.Router();
.
.
.
router.post('/', function(req, res) {
    var myVar = undefined;
    ...
    ...
    myVar = myFunc(); // WORKS!
    ...
    ...
}

myFunc = function() {
    ...
}

更多关于这个在我贫血的小博客上:可怜的误解var

为什么节点 js 中函数表达式的位置不重要?

确实如此。您没有遇到麻烦的唯一原因是在调用您传入的回调myFunc之前不使用它,这是您的模块脚本的顶级范围代码运行之后(包括表达式创建)。router.postmyFunc

例如,会发生什么:

  1. 准备工作(创建变量router并将myFunc它们设置为undefined

  2. 调用,它express.Routerrouter

  3. 调用router.post,传入但不调用回调函数

  4. 创建函数,该函数为myFunc

  5. 稍后,当请求进入时,回调被调用,此时时间myFunc已经创建(并且可以访问,因为回调myFunc是声明的上下文的闭包)

这与此类似:

setTimeout(function() {
    var myVar = myFunc();
}, 0);

var myFunc = function() {
    // code here...
}

首先setTimeout调用,然后创建函数并将其分配给myFunc,然后调用回调函数并通过 调用该函数myFunc

于 2015-12-07T16:53:22.540 回答