什么是预解析
JavaScript属于编程语言,JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
- 预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。
- 代码执行: 从上到下执行JS语句。
预解析会把变量和函数的声明在代码执行之前执行完成。
预解析也叫做变量、函数提升。
变量提升(变量预解析): 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
函数提升: 函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
案例1
我们来看下下面这个例子,大家觉得最后的运行结果是什么呢?
<script>
var num = 1;
function demo() {
console.log(num);
function demoSon() {
num = 3;
console.log(num);
}
var num = 2
demoSon();
}
demo();
</script>
运行结果是 underfined
和你预想的是否有差距呢?
我们来分析以下他的执行步骤:
// 相当于顺序执行了以下操作----------------------------
// 变量提升
var num;
// 函数提升 , 但不会调用 ,不调用不执行
function demo() {
// 当前作用域(即函数demo()里面) 变量提升
var num; 执行3. 当前作用域内定义一个num
// 当前作用域(即函数demo()里面)函数提升 不调用不执行
function demoSon() {
// 未定义直接赋值,此时作用域链指向demo()中的num
num = 3;
}
console.log(num); 执行4、打印num 作用域链指向执行3的num(当前作用域函数demo内)
定义未赋值 所以结果为underfined
num = 2 执行5. 给函数demo里面的num赋值 打印在前,赋值在后
demoSon(); 执行6. 调用demoSon()后demo中的num 值变为3; 全局变量num不做更改
}
//提升变量但是变量赋值不会提升
num = 1; 执行1. 给num 赋值为1
demo(); 执行2. 调用demo(
案例2
下面是一个经典的面试题
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
执行结果如下:
我们也来分析一下这个案例的执行过程:
// 相当于顺序执行了以下操作----------------------------
//函数提升到最前
function f1() {
//当前作用域(函数f1内)变量提升到最前
var a;
a = b =c = 9;
//var a = b = c = 9;
等同于var a = 9 ; b = 9 ; c = 9 ;
// b 和 c 直接赋值没有var声明 函数中没有声明直接赋值当全局变量看
此时 a 在函数中被定义,属于局部变量只能在函数内使用。 b与c为全局变量
//与集体声明不一样 var a = 9, b = 9 , c = 9;
console.log(a); 执行2. 打印a 结果为 9
console.log(b); 执行3. 打印b 结果为 9
console.log(c); 执行4. 打印c 结果为 9
}
f1(); 执行1. 调用f1()
console.log(c); 执行5. 打印c 结果为 9
console.log(b); 执行6. 打印b 结果为 9
console.log(a); 执行7. 打印a 结果报错,全局变量a未被定义
总结
- 预解析就是执行JavaScript代码前,浏览器会默认把带有 var 和 function 声明的变量在当前作用域下进行提前声明或者定义,提前声明的变量,赋值不会提升,函数不调用不会执行。
- 变量定义只在当前作用域有效,作用域之外视为未被定义
- 函数中没有声明直接赋值的变量当全局变量看
- 作用域、预解析会影响代码的执行结果,需要仔细分析。