# 声明提升(Hoisting)

在JavaScript中,函数以及变量的声明都将被提升到函数的最顶部。也就是变量可以使用后再声明

x = 5;
console.log(x);
var x

这是因为“Hoisting”——声明提升

函数声明和变量声明总是会被解释器“提升”到方法体的最顶部

# 1.不会提升初始化

// 第一组代码
var x = 5;
var y = 7;
console.log(x,y);
// 第二组代码
console.log(a,b);
var a = 9;
var b = 11;
// 第三组代码
console.log(t);

对比上面三组输出结果

第一组输出结果是: 5 7

没有异常

而第二组输出,按照我们的理解,会把声明提升到console.log()之前,那应该会输出9 11

但是输出结果并不是,而是undefined undefined

再看第三个输出,是报错,t is not defined

第二个输出组显然是a和b已经声明了,但是未定义,而t呢,则是没有声明

因此第二组代码在解释器中的情况实际上是这样子的:

var a;
var b;
console.log(a,b);
a = 9;
b = 11;

输出的结果,便是 undefined undefined

# 2.与函数相关的

我们先看一下这段代码的对比

// 第一组代码
console.log(a);
var a = 233;
a = function () {
	console.log('233');
}
console.log(a);
//==============================//
// 第二组代码
console.log(b);
var b = 666;
function b () {
    console.log('666');
}
console.log(b);

按照前面的了解,第一组代码中 var a将会被提前,因此第一个console.log(a)的输出应该是undefined

执行完了console.log(a)之后,a被赋值为233,然后又被赋值为一个函数

因此第二个console.log(a)的输出,则是函数里的内容

f a () {
	console.log(233)
}

在第一组代码中,函数是通过赋值的方式定义的,因此不会被提前,而接下来我们看到第二组代码

在第二组代码之中,var b将会被提前,那么function b(){}会不会提前呢?

答案是会的,这里的函数b采用的是声明法,函数声明和变量声明都被提前,因此,第二组代码在解释器中顺序如下:

function b () {
	console.log('666');
}
var b;
console.log(b);
b = 666;
console.log(b);

因此输出的内容是

f b () {
	console.log(666)
}
666

需要注意的是,在函数声明和变量声明都提升的情况下,函数声明会在变量声明之前

因此我们看到这组代码

console.log(c);
// 函数声明
function c () {
	console.log('8080');
}
var c = 8080;
// 函数表达式
c = function () {
	console.log('8080test');
}
console.log(c);

输出结果如下:

f c () {
	console.log('8080');
}
f () {
	console.log('8080test');
}

这里也引出了函数声明与函数表达式的区别

通过函数声明定义的函数,在整个作用域中无论前后都可以调用

但通过函数表达式定义的函数,需要在其赋值的位置之后才可以调用

顺带一提,有没有发现,函数声明的函数经过console.log()出来后,多了个c?应该说,通过函数表达式之后少了个c?

是因为 c = function () {} 赋值给c的是一个匿名函数,我们可以c = function xxx () {} 看看是一个怎么样的情况

# 3.let 与 const

let 与 const都必须先定义再使用,因此:

console.log(a);
var a = 233;
console.log(b);
let b = 666;

会发现,console.log(b)无法执行

再者,const必须在定义的时候就进行初始化,更不可能提前。

# 4.总结

总的来说,声明提前会带来一定的问题和影响,也容易造成一些不良的习惯。

在编写代码的时候应该注意在每个作用域开始前声明变量与函数,避免问题发生,也符合JavaScript的解析步骤,易于理解。

同时随着使用的技术不断更新,更多的采用ES6新增的,用于弥补var关键字一系列漏洞的,关键字 let 和 const,养成良好的编程习惯与风格。

更新时间: 6/21/2021, 10:16:30 PM