Skip to main content

变量和函数的声明提升

一、变量声明提升

大部分编程语言都是先声明变量再使用,但在 JS 中有些不一样:

console.log(a)  // undefined
var a = 10

上述代码正常输出 undefined 而不是报错,这是因为声明提升(hoisting),相当于如下代码:

var a;          // 声明
console.log(a); // undefined
a = 10; // 赋值

二、函数声明提升

创建函数有两种方法:

  • 通过函数声明 function foo() { }
  • 通过函数表达式 var foo = function () { }

这两种在函数提升有什么区别呢?

console.log(f1)           // function f1(){}
function f1() { } // 函数声明
console.log(f2) // undefined
var f2 = function () { } // 函数表达式

前面说过变量和函数都会上升,遇到函数表达式 var f2 = function () { } 时,首先会将 var f2 上升到函数体顶部,因此 f2 的值为 undefined

注意:当遇到函数和变量同名且都会被提升的情况,函数声明优先级更高,因此变量声明会被函数声明所覆盖,但是可以重新赋值。

console.log(a);   // ƒ a() { alert('我是函数') }

var a = '我是变量1';
function a() { alert('我是函数') }
var a = '我是变量2';

console.log(a); // 我是变量2

function 声明的优先级比 var 声明高,也就意味着当两个同名变量同时被 functionvar 声明时,function 声明会覆盖 var 声明,以上代码等效于:

function a() { alert('我是函数') }
var a;

console.log(a); // ƒ a() { alert('我是函数') }

a = '我是变量1';
a = '我是变量2';

console.log(a); // 我是变量2

再看个复杂点的例子:

function test(arg) {
// 1. 形参 arg 是 "hi"
// 2. 因为函数声明比变量声明优先级高,所以此时 arg 是 function
console.log(arg);
var arg = 'hello'; // 3. var arg 被忽略,arg = 'hello' 被执行
function arg() {
console.log('hello world')
}
console.log(arg);
}
test('hi');

/*输出:
ƒ arg() {
console.log('hello world')
}
hello
*/

当函数执行时,会先形成一个新的私有作用域,然后依次按如下步骤执行:

  1. 如果有形参,先给形参赋值。
  2. 进行私有作用域中的预解释,函数声明优先级比变量声明高,最后后者会被前者所覆盖,但是可以重新赋值。
  3. 私有作用域中的代码从上到下执行。