前提
众所周知啊,变量提升和函数提升基本上是面试必问,是基础中的基础。那么变量提升到底是个啥呢?通俗点讲,就是在JavaScript里啊,函数和变量的声明总是会被提升到当前作用域的最顶端。
看下面的例子:
// 第一个小例子
a = 1;
var a;
console.log(a);//输出 1
// ???为什么输出1呢 按照程序自上而下的执行的概念,不应该输出undefined吗!!
// 第二个小例子
console.log(b);
var b = 2;
// 你觉得这个例子运行是报错还是输出2呢?
首先我们来解析一下第一个例子,按照程序自上而下的执行的概念,应该输出undefined。但是,JavaScript并不是一门严格的自上而下执行的语言。为什么这么说呢?原因就来源我们今天讲的变量提升。 其实根据变量提升,第一个例子可以看成以下代码:
var a;
a = 1;
console.log(a);
这样子就好理解了吧。然后我们看看第二个例子,你觉得它是报错还是输出2呢?其实都不是,它会输出undefined,因为在前面我们说了,变量提升是提升变量的声明,而非变量的赋值,而对于JS来说,以下代码是等价的。
var b = 2;
//上下代码其实是等价的
var b;
b = 2;
所以它会输出undefined。
分析原因
想要知道原因,我们首先得知道JavaScript在运行时经历了什么。
其实在JavaScript运行时,一共经历了两个阶段:
- 预编译阶段
- 执行阶段
任何代码运行前都会经历预编译阶段,但它占用的时间往往极其短暂,所以我们一般感知不到,它主要是在内存中开辟一些空间以此来存放变量与函数。预编译时,JS会搜集所有的变量声明并且提前声明变量,而其他的语句都不会改变他们的顺序,并且,变量提升后,会给变量设置默认值undefined,给函数赋值函数体。所以你可以认为,预编译后,代码中的变量声明全部被提升到代码开头,其他代码位置不变。
逐渐深入
上面我们的例子只引入了变量,现在我们再来尝试引入函数。首先看下面这个例子
a();
function a() {
console.log('a');
}
var a = 1;
你觉得它会输出什么呢?他是不是等同于
var a;
function a() {
console.log('a');
}
a();
a = 1;
乍一看,你是不是觉得这肯定undefined啊!但是它还是输出了a,究其原因,就是当函数声明与其他声明一起出现的时候,函数声明高于一切,因为函数是JS的“第一公民”。
了解完之后,我们再看一个例子。
showName()
var showName = function() {
console.log(2);
}
function showName() {
console.log(1);
}
showName();
它变量提升后是什么样子呢?
function showName() {
console.log(1);
}
var showName;
showName();
showName = function() {
console.log(2);
}
showName();
这里的输出结果,我们来推导一下:
-
首先根据函数是JS的第一公民,第一个showName()读取到的应该是showName = function() { console.log(1);}此时输出1。
-
然后代码继续向下运行,showName()读取到 function showName() { console.log(2); }将一开始读取的 function showName() { console.log(1); }覆盖,从而在最后一行的showName()输出2。 所以它的输出结果为1 2。
-
解决了这些问题,又有一个疑问出现了,既然函数是JS的“第一公民”,那么当多个同名函数同时声明时,具体会发生什么呢?让我们看看下面的代码:
showName();
function showName() {
console.log('a');
}
function showName() {
console.log('b');
}
它的输出结果为 b 。 为什么呢?因为在有多个函数声明时,最后面的函数声明会替代前面的函数声明。
总结
从上面这些例子分析啊,我们可以总结3个小tips:
- 所谓的变量提升(变量提升),是指在JS代码执行中, JavaScript引擎(V8)把变量的声明部分和函数的声明部分提升到代码开头的行为,变量提升后,会给变量设置默认值undefined,给函数赋值函数体。
- 在JS的变量提升中,提升的只是变量的声明,所以对于var a = 1,一般把它拆分成var a 和 a = 1。只提升var a,a = 1不变。
- 有多个同名变量声明时,函数声明会覆盖其他的声明。如果有多个同名函数声明,则是由最后的一个函数声明覆盖之前所有的声明。
如有侵权,请联系删除。
作者:叨叨不是刀刀
链接:https://juejin.cn/post/6951223024053911560
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论区