Javascript 中的命名函数在声明前可访问,但函数文字不是

Named functions in Javascript accessible before declaration, but function literals aren't

我正在尝试弄清楚它是如何工作的。当我引用一个尚未声明的命名 Javascript 函数时,在某些情况下,它可以工作。但是如果我使用函数文字,它不会,但它也不会因 ReferenceError.

而失败
function works() {
    var works_ref = foo;
    function foo() {
        console.log('ok');
    };
    console.log('works ' + works_ref);
}

function fails() {
    var fails_ref = foo;
    var foo = function() {
        console.log('ok');
    };
    console.log('fails ' + fails_ref);
}

works();
fails();

这个returns

"works function foo() {
            console.log('ok');
        }"
"fails undefined"

我想知道第一个示例是如何工作的——这是一种解释型语言,没有编译,所以我希望任何类型的前向引用都会失败——为什么第二个示例不生成 ReferenceError?

function foo() {
    console.log('ok');
};

这叫做函数声明。这将在编译时处理。所以,JavaScript 知道有一个叫做 foo 的函数。这就是它在这里分配函数对象的原因

var works_ref = foo;

第二种情况,

var foo = function() {
    console.log('ok');
};

foo是一个变量,在函数后面声明。所以,因为 hoisting

var fails_ref = foo;

知道 foo 是在函数的某处定义的,但它不知道它的实际值。因为赋值 var foo = function() {} 发生在运行时。这就是为什么默认值 undefined 用于 foo 直到执行实际赋值语句。

这是因为吊装,实际情况是这样的:

function works() {
    var works_ref = undefined;

    function foo() {
        console.log('ok');
    };

    works_ref = foo;

    console.log('works ' + works_ref);
}

function fails() {
    var fails_ref = undefined, 
        foo = undefined;

    fails_ref = foo; // <---------- note this line.

    foo = function() {
        console.log('ok');
    };

    console.log('fails ' + fails_ref);
}