函数声明和变量声明都会被提升。但一个微妙的细节(可以 在拥有多个“重复的”声明的代码中出现)是,函数会首先被提升,然后才是变量。

    考虑这段代码:

    1. foo(); // 1
    2. var foo;
    3. function foo() {
    4. console.log( 1 );
    5. }
    6. foo = function() {
    7. console.log( 2 );
    8. };

    1 被打印了,而不是 2!这个代码段被 引擎 解释执行为:

    1. function foo() {
    2. console.log( 1 );
    3. }
    4. foo(); // 1
    5. foo = function() {
    6. console.log( 2 );
    7. };

    注意那个 var foo 是一个重复(因此被无视)的声明,即便它出现在 function foo()... 声明之前,因为函数声明是在普通变量之前被提升的。

    虽然多个/重复的 var 声明实质上是被忽略的,但是后续的函数声明确实会覆盖前一个。

    1. foo(); // 3
    2. function foo() {
    3. console.log( 1 );
    4. }
    5. var foo = function() {
    6. console.log( 2 );
    7. };
    8. function foo() {
    9. console.log( 3 );
    10. }

    虽然这一切听起来不过是一些有趣的学院派细节,但是它强调了一个事实:在同一个作用域内的重复定义是一个十分差劲儿的主意,而且经常会导致令人困惑的结果。

    在普通的块儿内部出现的函数声明一般会被提升至外围的作用域,而不是像这段代码暗示的那样有条件地被定义:

    1. foo(); // "b"
    2. var a = true;
    3. if (a) {
    4. function foo() { console.log( "a" ); }
    5. }
    6. else {
    7. function foo() { console.log( "b" ); }
    8. }

    然而,重要的是要注意这种行为是不可靠的,而且是未来版本的 JavaScript 将要改变的对象,所以避免在块儿中声明函数可能是最好的做法。