小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
一道好的面试题是不会轻易难倒应聘者,而且可以根据应聘人员答案来考察其功底深厚程度这才是好的面试题。而且有些知识我们看似已经了解了,但是如果对其深究似乎我们又不懂了。从事了几年前端 JavaScript 开发,当有人问道一些问题,通过经验似乎可以给出答案,而是如果人家再去深究或者举出范例,自己通常也就是变得束手无措,剩下的只是挠头。因此今天想去深入地聊一聊一些 JavaScript 中那些难点,对其进行进一步了解。
什么是 Hoisting(变量提升 )
hoisting 翻译过来是变量提升,也就是变量和函数的声明会在物理层面移动到代码的最前面,其实并不是真的把代码移动到了最前面而是编译阶段进行了优化。
- Hoisting 回答的是什么时候以及如何去访问你应用中声明变量。
- 值得注意的是这里谈到 Hosting 是
var这个词相关联,对于let和const则略有不同
那么什么是变量提升(Hoisting)
function aFunc(){
console.log(`I'm a function`);
}
aFunc()
上面代码看了之后应该没有任何疑惑,声明了一个函数aFunc 然后调用该函数aFunc
aFunc()
function aFunc(){
console.log(`I'm a function`);
}
但是这个就不一样了,因为在还没有声明函数就调用函数,运行代码没有报错,之所以能够正常运行这就要归功于 Hoisting
function anotherFunc(){
var aVar = "I'm a var";
console.log(aVar);
}
anotherFunc();
function anotherFunc(){
aVar = "I'm a var";
var aVar;
console.log(aVar);
}
anotherFunc();
这个代码是在我们声明一个变量前就为这个变量进行了赋值,然后将其输出。我们直到对于没有 var 声明变量这个变量是全局变量。
var aVar = "I'm a var";
function anotherFunc(){
var aVar;
console.log(aVar);
}
anotherFunc();
可能会认为这里输出 aVar 是 undefined,因为
如何实现变量提升
执行上下文(execution context)
- 编译(compile)
- 执行(execution)
会经过两个阶段分别是编译和执行,先是编译阶段,然后是执行阶段。因为今天讨论的内容仅与编译(compile)有关系,
在编译阶段,JavaScript 引擎会检查函数,并在内存中为所有的变量和函数声明创建一个空间,当编译阶段完成后,在随后的执行阶段中才真正运行你的代码。这样你了解了为什么当你在运行代码时,即使变量和函数声明在你访问或调用他们之后也还是可以正常运行的了吧。,JavaScript引擎也已经为你把它们储存在内存中了,但是也有一些特殊情况,请看下面的例子
function imNotSure(){
console.log(tellMe);
var tellMe = "Doesn't matter"
}
imNotSure()
大家可以想一想 console.log(tellMe) 输出的是什么,我们来简单地分析一下,如果你没有学习过 Hoisting(变量提升) ,可能因为会抛出 ReferenceError: tellMe is not defined 这个异常,如果你学习过 Hoisting,可能会猜到 Doesnt't matter 其实最终结果可能让你出乎意料是 undefined 这是为什么呢? 解释给你听。
我们把 var tellMe = "Doesn't matter" 分为 2 步骤,第一个步骤是声明变量 var tellMe 第二个步骤是 tellMe = "Doesn't matter" 变量赋值,变量提升只是针对于 var tellMe 变量声明,所以上面代码可以在执行可以想象这个样子,注意用词呀,是想象而不是真正这样,代码位置并没有变换。
function imNotSure(){
var tellMe
console.log(tellMe);
tellMe = "Doesn't matter"
}
doesThisWork();
var doesThisWork = function(){
console.log("does this work")
}
怎会抛出异常
TypeError: doesThisWork is not a function
什么会抛出异常呢,大家可以用上面对于变量提升解释定义来解释一下,也就是变量提升只是提升变量声明而不是变量赋值,这里 var doesThisWork 声明了一个变量,变量声明默认值是 undefined 然后调用 undefined 因为 undefined不是函数所以如果将其当做函数调用就会抛出 TypeError错误。
接下来我们再来看一个例子,还是先是大家思考思考 console.log 输出的内容
function imNotSure(num){
console.log(num);
var num = 3;
}
imNotSure(10)
可能大家给出答案是 undefined ,不过正确答案是 10 ,而不是 undefined。我们来解释一下,先用变量提升对下面代码进行变换一下
function imNotSure(num){
var num;
console.log(num);
num = 3;
}
其实大家仔细观察就不难发现这个函数多了一个参数 num,所以上面函数看成
function imNotSure(num){
var num = 10;
var num;
console.log(num);
num = 3;
}
但是即使看到上面代码,我们依旧给出答案是 undefined,其实我们首先看一下 var num = 10 也可以将这个语句拆分为两部分变量声明和变量赋值,而且我们再考虑 hosting 就会变成下面样子
function imNotSure(num){
var num;
var num;
num = 10;
console.log(num);
num = 3;
}
看到这里大家应该明白了吧。