预解析
JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript解析器在运行JavaScript代码的时候分为两步:预解析和代码执行。
-
预解析的时候js引擎会把js代码里面所有的var还有function提升到当前作用域的最前面。预解析分为两种:(1)变量预解析(变量提升):就是把所有的变量声明提升到当前作用域的最前面,不提升赋值操作。(2)函数预解析(函数提升):就是把所有函数声明提升到当前作用域的最前面,不调用函数。
-
代码执行的时候会按照代码书写的顺序从上往下执行
简单来说就是:js代码执行时会先把所有的声明 var 和 function 提升到当前作用域的最前面,而赋值的位置不变,然后从上往下执行。
光用文字描述难以理解,用几个简单的例子更容易快速掌握。
例1:变量预解析
console.log(num);
var num = 10;
以上这段代码的输出结果为:undefined。
原因:由于预解析的缘故,var声明的num被提到当前作用域最前面,实际上代码执行的逻辑顺序为:
var num;
console.log(num);
num = 10;
根据代码执行的逻辑顺序,可以知道num输出之前只声明未定义,所以输出结果就是 undefined(未定义)。
例2:变量预解析
fun();
var fun = function() {
console.log(22);
}
以上代码输出结果为:
报错了,这里又是为什么呢?还是因为预解析。我们再次按照预解析的逻辑,来将逻辑顺序写出来:
var fun;
fun();
fun = function() {
console.log(22);
}
根据上面预解析之后代码实际的逻辑顺序,我们可以知道在调用函数时fun时,函数fun并未被声明,所以输出结果报错:fun is not a function。所以函数表达式的调用必须写在函数表达式的下面才不会报错。
再来几个案例巩固一下:
例1
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
根据预解析,可以得到代码实际执行顺序为:
var num;
function fun() {
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
所以,输出结果为 undefined。
例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);
num = 20;
console.log(num);
}
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);
console.log(b);
a = '123';
}
a = 18;
f1();
执行代码:得到的结果为:
例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);//报错
}
执行结果为: