变量和函数的声明提升
一、变量声明提升
大部分编程语言都是先声明变量再使用,但在 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
声明高,也就意味着当两个同名变量同时被 function
和 var
声明时,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
*/
当函数执行时,会先形成一个新的私有作用域,然后依次按如下步骤执行:
- 如果有形参,先给形参赋值。
- 进行私有作用域中的预解释,函数声明优先级比变量声明高,最后后者会被前者所覆盖,但是可以重新赋值。
- 私有作用域中的代码从上到下执行。