前言
相信很多前端er都经历过这样的面试场景:
面试官:说一说let、var的区别? 我:let是ES6的,具有块级作用域的概念,且没有变量提升的特性。var有变量提升的特性。 面试官:来展开说说变量提升? 我:阿巴阿巴阿巴。。。
今天我们来彻底搞清楚变量提升,以后面试官再问起来,我们也能五花八门的说啦
提升
首先我们应该明确一点,提升的仅仅是声明,其次,提升这件事是发生在变量所声明的当前作用域内。可以简单理解为引擎在编译阶段会有一些优化行为,比如预先收集作用域中声明的信息,为了之后更快的找到和使用它们。 有同学开始问了:“到底啥是变量提升,为啥我平时都没见过?”,举个栗子,思考下面代码执行后打印的结果。
console.log('1', name)
var name = 'jack'
getName()
function getName () {
console.log('2': name)
}
让我们自上而下分析代码。第一行的变量name会打印undefined,因为第三行的声明提升到了最前面。到第二行结束,name才完成了赋值操作。注意到了吗?var name = 'jack'
虽然是一句代码,但实际上它分为两步,先声明(存在提升),在赋值(不会被提升)。接着到第三句代码,执行函数,这时全局变量name已经完成赋值所以打印出‘jack’。
如果我们把第三行代码与第二行代码调换位置,第二个打印结果又是什么呢?大家可以思考下。下面我们具体来看看提升这件事。
声明提升
我们知道,使用一个未声明的变量,将会报错ReferenceError: xx is not defined
,而使用一个声明但为赋值的变量,会返回undefined
。我们也知道函数定义的方式有 函数声明 和 函数表达式,注意函数表达式不会被提升。
变量声明
首先来看下变量声明提升,我们对它进行变形,可以轻松得到打印结果。
num = 0
var num
console.log(num)
count = 1
var count = 2
console.log(count)
通过变量声明提升的原则上述代码等价于以下代码:
var num
num = 0
console.log(num) // 0
var count
count = 1
count = 2
console.log(count) // 2
函数声明
再来看下函数声明提升,以下代码,思考执行后的打印结果:
getAge(1)
getCount(1)
// 函数表达式 + 具名函数
var getAge = function toAge (index) {
console.log(index)
}
// 函数表达式 + 匿名函数
var getNum = function (index) {
console.log(index)
}
// 函数声明
function getCount (index) {
conosle.log(index)
}
getAge(2)
getCount(2)
同样我们利用声明提升的原则进行变形,得到如下代码:
// 函数声明
function getCount (index) {
conosle.log(index)
}
var getAge
var getNum
getAge(1) // getAge is not a function
getNum(1) // getNum is not a function
getCount(1) // 1
// 函数表达式 + 具名函数
getAge = function toAge (index) {
console.log(index)
}
// 函数表达式 + 匿名函数
getNum = function (index) {
console.log(index)
}
getAge(2) // 2
getNum(2) // 2
getCount(2) // 2
正如我们前面说的,函数表达式没有提升,所以在定义之前执行函数会报类型错误,因为此时他们只有变量提升了,getAge
和 getNum
此时为undefined
。
声明优先级
当变量声明和函数声明相遇,函数声明才是老大哥前排坐~
console.log(a) // [Function: a]
var a = 2
function a () {}
console.log(a) // 2
注意,函数声明优先于变量声明,也就是说,函数声明会处于作用域顶部,其次才是变量声明。
总结
通过上面的各个代码示例,相信对变量提升有了一定的了解,可以变换示例中代码的顺序查看输出结果的变化,来考察自己是否真的理解了。只要我们把握声明提升的原则,就能以不变应万变。下面简单总结以下:
- var具有变量提升的特性,会把变量声明提升到当前作用域的最前面,但是赋值操作不会被提升;
- 函数声明会被提升,但是函数表达式不会被提升,无论函数表达式后面跟着是具名函数还是匿名函数都不会被提升。
- 函数声明提升的优先级高于变量声明,函数声明会被提升到当前作用域的最顶部,其次才是变量声明。
靓猫镇楼,还望轻拍~在评论区一起分享学习交流吧~