1 明确预解析的过程:浏览器在执行代码的时候,会对整体进行预解析,作用是为了排除错误以及提升变量和函数。
2 变量提升仅仅提升用 var 声明的变量,先提升变量在提升函数;
3 当函数被调用的时候,函数体内的代码又会进行相同的解析过程;
4 解析完毕之后,浏览器一行一行的执行代码;
5 案例解释:
var a = 18 ;
f1();
function f1(){
var b = 9 ;
console.log(a);
console.log(b);
var a = "abc";
}
解析过程:
提升变量和函数
var a ;
function f1(){
var b = 9 ;
console.log(a);
console.log(b);
var a = "abc";
}
//一行一行执行代码
a = 18 ;
f1();
//执行到上面这一行代码的时候,函数被调用,开辟一块独立的内存区 ,在函数体内又会进行同样的解析过程
function f1(){
var b ;
var a ;
b = 9 ;
console.log(a);
console.log(b);
a = "abc";
}
//解析完毕
以上代码输出结果为:undefined 9.
注意两个问题:
1 函数体被提升的时候,并不会被执行;
2 变量的使用会遵循“就近原则”,即,如果在函数内部有定义的变量,那么就会在当前作用域下找当前作用域下声明的变量, 如果在当前作用域没有声明该变量,则会在上一级作用域找变量那么外部的变量不会被调用
这就解释了 a 输出的结果是 undefined;
变身1 :
var a = 18 ;
f1();
function f1(){
var b = 9 ;
console.log(a);
console.log(b);
a = "abc";
}
以上代码输出结果为 18 9 ;
此时, a 调用的是全局变量 a = 18 ;可能有的人 会问为什么不是 a = “abc” ;还是回到浏览器的解析过程:提升变量和函数的 声明,然后 一行一行执行代码。
去掉函数体内 a 的 var 声明,此时 a 是隐式全局变量,函数体 f1()整体被执行完毕之后,外部的全局变量 a 会被重新赋值为 “abc ”。
变身2 :
var a = 18 ;
f1();
function f1(){
var b = 9 ;
console.log(a);
console.log(b);
a = "abc";
console.log(a);
}
console.log(a);
输出的结果为 18 9 abc abc .(代码是一行一行执行的,只有当执行到 a = “abc”,那一行。隐式全局变量 a 才可以改变 全局变量 a 的值。
变身3 :
var a = 18 ;
f1();
function f1(){
var b = 9 ;
console.log(a);
console.log(b);
a = "abc";
console.log(a);
var a ;
}
console.log(a);
输出结果是 :undefined 9 abc 18
注意函数体内的用 var声明的变量都是局部变量,在该函数体内的局部作用域有效,就只能在该函数中访问该变量。当退出该函数后,这个变量会被撤销。这种变量称为本地变量。可以在不同的函数中使用名称相同的本地变量,这是因为只有声明过变量的函数能够识别其中的每个变量。
在调用 f1() 的时候,函数体内的预解析如下:此时函数体内的 a 是局部变量
function f1(){
var a ;
var b ;
b = 9 ;
console.log(a);
console.log(b);
a = "abc";
console.log(a);
}
变身4 :
var a = 18 ;
function f1(){
var b = 9 ;
console.log(a);
console.log(b);
a = "abc";
console.log(a);
}
console.log(a);
输出结果为 18 ,有的同学可能会疑问,为什么隐式全局变量 a = “abc “,没有覆盖掉 a = 18 的值呢? 根本一句话:当没有调用函数的时候,即是函数体内有隐式全局变量,也不会被执行。(函数里面的代码块只有在被调用的时候才会被声明执行)。