前言
相信学习过js的人都听说过这两句话:
- 函数声明整体提升
- 变量声明提升
这两句话是预编译的简化版,当然只会这两句话做项目的过程遇到一些问题时没有办法解决的,那么本篇就从原理讲这个预编译,学完本篇保证预编译的面试题、以及项目中的bug,通通解决。
一、Js运行过程
首先我们要学习Js的运行过程,这样才会更容易理解这个预编译,我们都知道Js是单线程的解释性语言。
Js运行总共有三部:
- 语法分析:在运行之前先给你检测一遍你这个代码,保证你能运行
- 预编译:在函数执行的前一刻,会创建一个叫做执行期上下文的(AO)对象这个创建执行期上下文的过程叫做预编译。
- 解释执行:前两部都没问题,开始解释代码然后执行
那么第一步和第三步都很简单,第二部也是很难理解的也是我们今天的主角:预编译
二、Js预编译
上面我们也说了,这个预编译发生在函数执行前,那么我们先来看一段代码
function test(a,b){
console.log(a);
console.log(b)
console.log(c)
console.log(d)
var c = 123;
function d(){
}
}
test(1);
那么这里的a我们可能大多数人都知道是1,那么b、c、d都输出什么呢?我们预编译就是解决这类问题的。
这个a、b、c、d的值都是从这个执行期上下文(AO对象)中获取值的,那么下面我们就来看看创建这个AO对象的过程也就是预编译:
- 创建AO对象 Activation object (执行期上下文)作用域
- 找形参和变量声 明,将变量和形参名作为AO属性名 ,值为undefined
- 将实参和形参值统一
- 在函数体里面找函数声明,值赋予函数体
那么我们再来看上面的代码,这回根据上面的四部曲,是不是就简单了很多呢
// 1. 首先创建AO对象
// AO{
// }
// 2. 找形参和变量声明,将变量和形参名作为AO属性名 ,值为undefined
// AO{
// a:undefined,
// b:undefined,
// c:undefined,
// }
// 3. 将实参和形参值统一 我们在传入的时候传入了一个1
// AO{
// a:1,
// b:undefined,
// c:undefined,
// }
// 4.在函数体里面找函数声明,值赋予函数体
// AO{
// a:1,
// b:undefined,
// c:undefined,
// d:function d(){
// }
// }
function test(a,b){
console.log(a);// 1
console.log(b);// undefined
console.log(c);// undefined
console.log(d);// function d(){}
var c = 123;
function d(){
}
}
test(1);
三、练习
那么学完,下面我准备了一道小题,给大家巩固一下知识。
function fn(a){
console.log(a);
var a =12;
console.log(a);
function a() {
}
console.log(a);
var b = function (){
}
console.log(b);
function d(){
}
}
fn(1);