入门小白基础篇之JavaScript预编译详解

 更新时间:2026年05月29日 10:51:04   作者:biubiubiu_LYQ  
js中的预编译是指在代码被执行前解释器对代码进行的操作,这篇文章主要介绍了入门小白基础篇之JavaScript预编译的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在了解预编译之前,我们应该先了解一下v8引擎是怎样工作的,首先它需要将代码分成一个个词法单元,如 'var' ,'a',等,再进行语法分析,将词法单元组成 AST(抽象语法树),最后根据AST生成代码执行。那么预编译就是发生在代码执行之前,让我们来看一个例子。

console.log(a);  //输出 undefined
var a = 1

按照大家所理解的代码执行步骤,应该是从上到下依次执行,那么它应该报错,但是最后显示的是undefined,这是为什么呢?这是因为在代码执行之前,它先进行了编译这个过程,那编译是怎么做呢?

var a  //定义变量 a  将它提升到当前作用域的顶部
console.log(a); // 得到undefined  找不到a的值
a = 1 

将变量提升到当前作用域的顶部,这个过程我们称之为声明提升,此处为全局作用域,所以得到输出结果为undefined,那为什么出现声明提升呢?我们就要具体了解一下预编译过程是怎么样的。

预编译

预编译发生在代码执行之前,它分为两类 函数体内的预编译和全局预编译,函数的预编译是在函数被调用时才触发,而全局预编译是在代码加载时就触发了,那它们有以下几个步骤。

1.函数体内的预编译

  1. 创建一个执行上下文 AO:{}
  2. 找形参和变量声明,将形参和变量名作为属性名,添加到AO中,值为 undefined
  3. 将形参和实参统一
  4. 在函数体内找函数声明,将函数名作为AO 中的属性名,函数体作为属性值

让我们来看一个例子,根据步骤依次梳理

function fn(a) { 
  console.log(a); 
  var a = 123 
  console.log(a);
  function a() {}
  var b = function() {}
  console.log(b);
  function c() {}
  var c = a
  console.log(c);
}
fn(1)  //调用函数 

首先 创造一个执行上下文 AO:{}

其次 找到形成和变量声明,将形参和变量名作为属性名,添加到AO中,也就是说找到 形参a 变量a b c 添加到AO中, 值为 undefined,即有

AO = {
a:undefined  //出现了形参a 又出现变量a 则进行覆盖 对象中只有一个key
b:undefined 
c:undefined 
}

然后将 将形参和实参统一那么 a此时 值为1,即有

AO = {
a:undefined →1
b:undefined 
c:undefined 
}

最后找到在函数体内找函数声明,将函数名作为AO 中的属性名,函数体作为属性值即有

AO = {
a:undefined →1→function a(){}
b:undefined 
c:undefined→function c(){}
}

已经完成预编译过程,那就开始执行代码,所以有

function fn(a) { 
  console.log(a); //                         输出结果 function a(){}
  var a = 123  // 把123赋值给a
  console.log(a); /                          输出 a值为123
  function a() {}
  var b = function() {} 把function(){} 赋给b
  console.log(b); //                         输出为 function(){}
  function c() {}
  var c = a  //把a赋给c c为123
  console.log(c); //                        输出123
  
// AO = {
// a:undefined →1 →function a(){} →123
// b:undefined → function b(){}
// c:undefined →function c(){} →123

}
fn(1)  //调用函数 

结果也正如我们所判断的这样

2.全局预编译

  1. 创建全局执行上下文 GO:{}
  2. 找全局变量声明,将全局变量名作为属性名,添加到GO中,值为 undefined
  3. 找全局函数声明,将函数名作为GO 的属性名,函数体作为属性值

依旧来看一个例子,根据步骤依次梳理

var a 
var b = 2
function a(){
    console.log(a);
    var c = 3
    var a = b
    function c(){}
    console.log(c);
}
a()
console.log(a);

首先,创建全局上下文GO:{}

其次,找全局变量声明,将全局变量声明作为属性名,添加到GO中,也就说将变量 a,b添加到GO中,值为undefined,即有

GO = {
    a: undefined, 
    b: undefined
}

最后,找全局函数声明,将函数名作为GO 的属性名,函数体作为属性值,即有

GO = {
    a: undefined →function a(){xxx}, 
    b: undefined
}

全局编译已经完成,开始执行代码,所以有

//GO = {
//    a: undefined →function a(){xxx}, 
//    b: undefined
//}

var a 
var b = 2   // 把 2 赋给 b
function a(){
    console.log(a);
    var c = 3
    var a = b
    function c(){}
    console.log(c);
}
a() //调用函数 function a(){}
console.log(a);  //输出 function a(){}

所以 11 行处代码 输出为function a(){},而代码 有a(),说明调用了函数function a(){xxx},那我们又需要对函数进行预编译,与上文步骤相同,所以我们可以得到

//GO = {
//    a: undefined→ function a(){xxx}, 
//    b: undefined
//}

var a 
var b = 2
function a(){

// AO = {
//   c: undefined→ function c(){}→ 3
//   a: undefined→ b 即 2
//}
  
    console.log(a);               //输出 undefined
    var c = 3   // 把3赋给c
    var a = b // 把b的值赋a 函数中没有,去外层找,得到b值为2 即a值为 2
    function c(){}  
    console.log(c);               //输出 3
}
a()
console.log(a);                  //输出 function a(){}

理解之后结果也是清晰明了起来

全局预编译GO与函数体内预编译AO的关系

1. 执行顺序:先全局预编译 → 再函数调用时执行函数预编译

2. 作用域层级:全局是最外层,代码执行时开始编译→函数预编译依附全局,形成层级作用域,只有当调用函数时才会开始编译

3. 优先级:函数内部变量 > 全局变量,内部优先访问自身预编译内容,找不到再去全局里面找,而全局找不到,不会去函数内部找 即(小可以去大找,大不会去小找)

4. 互不冲突:同名变量互不覆盖,只遵循作用域就近原则

到此这篇关于入门小白基础篇之JavaScript预编译的文章就介绍到这了,更多相关JS预编译内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript控制网页平滑滚动到指定元素位置的方法

    JavaScript控制网页平滑滚动到指定元素位置的方法

    这篇文章主要介绍了JavaScript控制网页平滑滚动到指定元素位置的方法,实例分析了javascript操作页面滚动的技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • 基于JavaScript实现自动更新倒计时效果

    基于JavaScript实现自动更新倒计时效果

    这篇文章主要为大家详细介绍了基于JavaScript实现自动更新倒计时效果,元旦倒计时代码分享,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • javascript 发布-订阅模式 实例详解

    javascript 发布-订阅模式 实例详解

    这篇文章主要介绍了javascript 发布-订阅模式,结合实例形式详细分析了javascript发布-订阅模式基本功能、原理、实现方法与相关使用技巧,需要的朋友可以参考下
    2023-06-06
  • js查错流程归纳

    js查错流程归纳

    归纳是为了更好的理解。平时同事有问题找我帮忙解决问题,往往都是很小的问题,这种情况他们并不是缺乏解决问题的知识,而是需要找到问题的办法
    2012-05-05
  • javascript 玩转Date对象(实例讲解)

    javascript 玩转Date对象(实例讲解)

    下面小编就为大家带来一篇javascript 玩转Date对象(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • 用原生js做个简单的滑动效果的回到顶部

    用原生js做个简单的滑动效果的回到顶部

    很多网页在下方都会放置一个“返回顶部”按钮,这样可以帮助访客重新找到导航或者重温一遍广告,于是将返回顶部功能做成了滑动效果
    2014-10-10
  • 监控微信小程序中的慢HTTP请求过程详解

    监控微信小程序中的慢HTTP请求过程详解

    这篇文章主要介绍了监控微信小程序中的慢HTTP请求过程详解,Fundebug 的微信小程序监控插件在 0.5.0 版本已经支持监控 HTTP 请求错误,在小程序中通过wx.request发起 HTTP 请求,如果请求失败,会被捕获并上报,需要的朋友可以参考下
    2019-07-07
  • JavaScript数据结构与算法之检索算法实例分析【顺序查找、最大最小值、自组织查询】

    JavaScript数据结构与算法之检索算法实例分析【顺序查找、最大最小值、自组织查询】

    这篇文章主要介绍了JavaScript数据结构与算法之检索算法,结合实例形式分析了顺序查找、最大最小值、自组织查询算法相关原理与实现技巧,需要的朋友可以参考下
    2019-02-02
  • 如何在CocosCreator里画个炫酷的雷达图

    如何在CocosCreator里画个炫酷的雷达图

    这篇文章主要介绍了如何在CocosCreator里画个炫酷的雷达图,对Graphics感兴趣的同学,一定要看看,并且把代码实践一下
    2021-04-04
  • 小程序实现列表多个批量倒计时

    小程序实现列表多个批量倒计时

    这篇文章主要为大家详细介绍了小程序实现列表多个批量倒计时,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02

最新评论