1.预解析
1.1引子
//1问
console.log(num);//报错 num未定义
//2问
console.log(num); //undefined 未报错
var num = 10;
//3问
fun();//11 未报错
function fun() {
console.log(11);
}
//把fun();放在后面、前面都不会报错
//4问
fun1();//报错 fun1 is not a function
var fun1 = function() {
console.log(22);
}
//把fun1();放在后面就不会报错
//综上,问2和文4都比较奇怪
- Js代码是由浏览器中的js解析器来执行的。js解析器在运行js代码的时候分为两步:预解析和代码执行。
- 预解析:js引擎会把js里面所有的var、function(这里指函数声明,不包括函数表达式)提升到当前作用域的最前面。
- 代码执行:按照代码书写的顺序从上往下执行
2.变量预解析和函数预解析
预解析分为变量预解析(变量提升)和函数预解析(函数提升)
2.1 变量提升 就是把所有的变量声明提升到当前作用域的最前面,不提升赋值操作。
对于之前的“问2”
//2问
console.log(num); //undefined 未报错
var num = 10;
相当于执行了以下代码
var num;
console.log(num); //undefined
num = 10;
对于之前的“问4”
//4问
fun1();//报错 fun1 is not a function
var fun1 = function() {
console.log(22);
}
//把fun1();放在后面就不会报错
相当于执行了以下代码
var fun1;
fun1();//报错 fun1 is not a function
fun1 = function() {
console.log(22);
}
值得注意的是这里的fun1是变量名,不是函数名,这里是函数表达式,是匿名函数。
2.2 函数提升 就是把所有的函数声明(注意是函数声明,不是函数表达式)提升到当前作用域的最前面, 不调用函数。
这就可用说明为什么在“问3”中,函数的fun();放在前后都不会报错,对于之前的问“问3”
fun();//11 未报错
function fun() {
console.log(11);
}
相当于执行了以下代码
function fun() {
console.log(11);
}
fun();//11 未报错
注意:由于函数表达式无法进行函数提升,所以函数表达式的调用必须写在函数表达式的下面
3.预解析案例
//案例1 会输出什么
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
相当于执行了以下代码
var num;
function fun() {
var num;
console.log(num); //undefined
num = 20;
}
num = 10;
fun();
//案例2
var num = 10;
function fn() {
console.log(num);
var num = 20;
console.log(num);
}
fn();
相当于执行了以下代码
//相当于执行以下代码
//由内而外地完成变量提升,在根据链式查找法,得到输出的结果
var num;
function fn() {
var num;
console.log(num); //undefined
num = 20;
console.log(num); //20
}
num = 10;
fn();
//案例3
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
相当于执行了以下代码
//相当于执行了以下代码
var a;
function f1() {
var b;
var a;
b = 9;
console.log(a); //undefined
console.log(b); //9
a = '123';
}
a = 18;
f1();
小tips:
var a = b = c = 9;
相当于
var a=9;
b=9;
c=9;
集体声明
var a = 9,b = 9,c = 9;
才相当于
var a = 9;
var b = 9;
var c = 9;
//案例4
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() {
var a;
a = b = c = 9;
console.log(a); //9
console.log(b); //9
console.log(c); //9
}
f1();
console.log(c); //9
console.log(b); //9
console.log(a); //报错 a is not defined
案例总结:先将代码按照预解析排列好,再按照作用域链去查找结果即可。