JavaScript基础——ES5变量提升(Hoisting)

爱因斯坦曾说:“提出一个问题往往比解决一个问题更重要。”

我们先来看下面这段代码会输出什么内容呢?

var a=1;
f();
console.log(a);
function f(){
    console.log(a);
    var a=2;
    console.log(a);
}

//输出结果:
undefined
2
1

这是hoisting的经典例子,涉及到函数声明和var变量声明两种提升方式,如果对输出结果理解有困难,follow本文一起学习吧!

1. 含义

在参考了很多教程后,对hoisting的含义归纳如下:

  • 变量和函数的声明都将被提升到作用域(ES5:全局作用域或函数作用域)的最顶部
  • 变量或函数可以先使用后声明
  • 只有声明被提升,而不提升初始化
  • 具体操作:当遇到<script>,js会进行预解析,将var变量声明和函数声明提升,但不会执行函数,最后再按上下文执行

如下图,ES5中的变量提升包含两种:(1)var声明的变量(2)函数,而函数的提升又分为函数声明和函数表达式。

                                         

关于对ES6中新增部分(let、const、class)的变量提升,之后我们会详细讲解。

2. 变量提升:var声明的变量

下面这段代码是用var声明变量,hoisting后会输出什么呢?

function f(){
    console.log(a);
    var a=2;
}
f();

//输出结果:
undefined

原因是js对于var声明的变量具有变量提升的特性,将所用的变量提升到作用域的最顶部,并赋值undefined。以上代码等价于

function f(){
    var a;
    console.log(a);
    a=2;
}
f();

注:没有var声明的变量会变成全局变量,也不具备变量提升的特性。

3. 变量提升:函数

函数的变量提升分为两种:函数声明(function+函数名)和函数表达式(将匿名函数赋值给变量),它们的提升规则和var变量声明相同,我们重点讲解函数和变量同时提升的问题。

当函数声明和变量同时提升,

console.log(f);
function f(){
}
var f=1;

//输出结果:
function f(){}

当函数表达式和变量同时提升,

console.log(f);
var f=function(){};
var f=1;

//输出结果:
undefined

为什么会出现两种不同的输出结果呢?

这是因为函数提升分为两种情况:

  • 函数声明:在提升时,会连同定义整个被提升上去,并且函数声明的优先级高于变量声明,等价于
function f(){
}
console.log(f);
f=1;    //变量声明只进行一次,因此function f()声明后,var f=1的声明会被忽略
  • 函数表达式:其实就是var声明的变量,因此看作是两个var变量就好了,等价于
var f;
console.log(f);
f = function(){};
f = 1;

4. 总结

1. 所有声明都会被提升到作用域的最顶部

2. 同一个变量声明只进行一次

3. 变量提升的优先级:函数声明 > 函数表达式 = var声明的变量

4. 函数声明的变量提升是连同定义一起,而其余两种只提升声明、不提升初始化

 本文是参考多篇博客之后总结的看法,与君共勉,如有错误欢迎指正。

猜你喜欢

转载自blog.csdn.net/huaf_liu/article/details/108954504