预解析
所谓预解析,就是在js代码解析之前,浏览器会把所有带var和function关键字声明地变量或函数进行提前地声明和定义
js代码的执行是分成两个阶段的,首先预解析,然后再一行一行去解析代码
预解析的过程 :
- 将var关键字声明的变量提升到所在作用域的最前面,赋值不会提升,默认值是undefined
- 将function关键字声明的函数提升到当前作用域的最前面,且同时会定义
- 函数表达式只用预解析左边那部分
- 如果函数重名,后面的会覆盖前面的函数名
- 如果函数名和变量名重名,函数名优先
- 函数中的预解析,参数也是要预解析的
光讲理论可能不太直观,现在我们通过一些例子来讲解
console.log(num);
var num=10;
最开始的时候可能会以为打印的num的值是10,其实打印的是undefined,我们把这段代码改写一下
‘
var num=undefined;//预解析,num默认值为undefined-
console.log(num);//执行到此处。num的值并没有发生变化,所以打印的是undefined
var num=10;
下面我们来讲讲函数预解析的情况,直接上一个例子
console.log(num);
num();
var num=10;
console.log(num);
num();
var num1=20;
function num(){
console.log(num1);
var num1=30;
}
结果为
这时候可能就有点乱了,没关系,我们一步步分析(注意,预解析是在自己的作用域里解析)
console.log(num);//预解析,由于函数与变量同名,函数优先,所以此处是打印函数体
num();//函数调用,函数内部预解析,具体看下面函数
var num=10;//num值改变
console.log(num);//10
num();//num已重新赋值,会报错,num不再是一个函数
var num1=20;
function num(){
//var num1=undefined;函数中的num1也是由var声明的,提升到函数作用域最前面
console.log(num1);//执行到此处,num1为undefined,此处就打印undefined
var num1=30;
}
上面这段代码,如果num函数中并没有 var num1的话,打印的就应该是全局变量num1的值,函数里要用一个变量,先在自己的函数作用域里找,找不到就沿着作用域链网上找,此处就不具体解释了。
此外我们可以再来看一下函数表达式的情况
say();//普通函数预解析,函数提升到作用域最前面,且同时定义,正常调用
function say(){
console.log('hello');
}
fn();//函数表达式预解析,只预解析左边那部分,即 var fn=undefined,所以会报错,fn并不是一个函数
var fn=function(){
console.log("我是函数表达式");
}
fn();
看一下实际效果
总结一下:程序最开始只对全局下的变量和函数进行预解析,当函数执行时,我们就去函数里面进行预解析。预解析完成之后,我们就一行一行去执行代码就可以了。