深度解析Javascript中的变量提升
> 大家好,我是前端老陈醋,有关js中的变量提升,很多小伙伴可能都会有疑问,尤其是面试的过程中有大量有关于变量提升相关的题,那么浏览器在解析js的过程中,js中的变量究竟是怎么提升的呢?想要彻底解决这些问题,就要理解浏览器是怎么解析js代码的,那么我们今天就来深度解析一下这个问题哈。
## 首先在JS中涉及两种作用域的问题,那么什么是作用域呢?
> 作用域是代码中所使用名字的作用范围,分为Script全局作用域和函数局部作用域。 当浏览器在解析网页内容时,会分别启动不同的解析器来解释代码的含义,如解析标签(超文本)的解析器、解析CSS样式的解析器,解析javascript脚本的解析器。且解析过程为同步(按顺序)解析。所以当浏览器解析到script标签时,会停止对html和css的解析,同时启动javascript的解析器。而在解析javascript的过程中我们主要关注解析器中的两个步骤:
1. 预解析,即在当前作用范围中去寻找var、function、形参这三个内容。
- 如果找到var关键字、则提取var后面的名字放到当前作用域中,且默认给这个变量初始化一个值为undefined。
- 如果找到function关键字,则提取函数名放到当前作用域中,且将整个函数块赋值给函数名。
- 如果找到形参,则将形参名放到当前作用域中,且默认初始化为undefined。这个过程也称为变量提升。
\2. 逐行解读代码(即从上到下依次执行每一条语句)且分为两个步骤:
- 执行表达式
- 函数调用。
```js
/*
一、预解析(寻找var function 形参)
i = undefined (进入script作用域时,找到var)
fn = function fn(){alert(2);} (进入script作用域时,找到function)
二、逐行解读代码(函数声明,直接跳过)
1. 执行表达式
2. 函数调用
*/
alert(i); //1. 当执行第一个表达式时,输出i的值为undefined
//第一个找到的是var,所以将i放到预解析中,初始化为undefined
var i = 1; //2. 当执行第二个表达式i = 1时,会在预解析中先找到变量i,将值修改为1
alert(i);//3. 当执行输出表达式时,在预解析中i的值 1 输出
function fn(){ //4. 函数声明,不执行,直接跳过
alert(2);
}
alert(i); //5. 当执行输出表达式时,在预解析中i的值 1输出
```
> 当变量名与函数名相同时:
```js
/*
一、预解析(寻找var function 形参)
a = undefined (在作用域中第一次找到var a) (在找到同名的函数a时,当前变量a被丢弃)
a = function a(){alert(2);} (在作用域中第二次找到 function a,所以在作用域同时出现一个变量a和一个函数a,此时,将变量a丢弃,保留函数a) (在找到下一个function a时,此时的函数 a 被覆盖)
a = function a(){alert(4);} (在作用域中第三次找到function a时,与前面是相同的函数 a,会将前面的函数a 进行覆盖)
a = 1 (当执行到a = 1时,上面的a = function a(){alert(4);} 将被覆盖成 1)
二、逐行解读代码(函数声明,直接跳过)
1. 执行表达式
2. 函数调用
*/
alert(a); // 1. 在执行该表达式时,预解析中只有 a = function a(){alert(4);} 所以此时的结果为 function a(){alert(4);}
var a = 1; // 第一次找到的 var a
alert(a); //2. 在执行该表达式时,预解析中的 a 值为 1 ,所以结果为 1
function a(){ //第二次找到的 a
alert(2);
}
function a(){ //第三次找到的 a
alert(4);
}
alert(a); // 3. 在执行该表达式时,预解析中的 a 值为 1 ,所以结果为 1
```
> 当有多个script标签时: - 多个script标签时,从上到下依次解析script作用域,所以建议将所有声明的语句放到第一个script中。
```html
<script>
/*
一、预解析(寻找var function 形参)
fn = function(){alert(2);} (在解析第一个script时,只找到一个funciton fn);
a = 1 (在解析第二个script作用域时,找到 var a)
二、逐行解读代码(函数声明,直接跳过)
1. 执行表达式
2. 函数调用
*/
alert(a); //报错,在执行该表达式时,因为在预解析中没有a变量,所以此时会报错。
function fn(){
alert(2);
}
</script>
<script>
var a = 1;
fn(); //2 在调用该函数时,在预解析中已经存在function fn,所以输出函数中的表达式 值为2
</script>
```
更多关于“web前端培训”的问题,欢迎咨询千锋教育在线名师。千锋已有十余年的培训经验,课程大纲更科学更专业,有针对零基础的就业班,有针对想提升技术的提升班,高品质课程助理你实现梦想。