js 预编译(js的底层知识,帮助新手更好理解js)

在讲预编译之前,我们要先了解声明提升、作用域和编译执行步骤。如果对它们还存疑惑,那可以先看看我这篇文章(js的作用域,声明提升和let,const与var的区别),如果没有,那我们继续。

预编译是指代码执行前编译的环节,但对于不同的作用域它的过程也有所不同

预编译发生在函数体内时

方法

  1. 创建函数的AO对象(Action Object) (其实就是作用域)
  2. 找形参和变量声明,将形参和变量声明作为AO的属性名,值赋予undefined
  3. 将形参和实参统一
  4. 在函数内找函数声明,将函数名作为AO对象的属性名,值赋予函数体

例子:

javascript 复制代码
    function fn(a) {
        console.log(a); 
        var a = 123
        console.log(a); 
        function a() {}
        console.log(a); 
        var b = function() {}
        console.log(b);
        function d() {}
        var d = a
        console.log(d);
    }
    fn(1)

让我们用上面的提供的方法来思考一下,这四个console.log()都将输出什么

  1. 创建函数的AO对象

    ini 复制代码
     AO = {
    
     }
  2. 找形参和变量声明,将形参和变量声明作为AO的属性名,值赋予undefined

    javascript 复制代码
     AO = {
         a: undefined
         // 注意,对象中key具有唯一性,上面代码中我们有一个形参a ,还有一个变量a , 但因为key的唯一性,所以此处不会出现两个a: undefined
         b: undefined
         d: undefined
     }

这里我们先聊聊什么是声明,像var a = 3;这样一行代码,其实它在编译器眼里是var a; a = 3,其中var a 就是在编译的时候声明一个变量a ,a = 3 是在执行的时候对a这个变量进行赋值,且值为3。函数在编译的时候不声明。

  1. 将形参和实参统一

    yaml 复制代码
     AO = {
         a: 1
         b: undefined
         d: undefined
     }
  2. 在函数内找函数声明,将函数名作为AO对象的属性名,值赋予函数体

    css 复制代码
     AO = {
         a: function a() {}
         b: undefined
         d: function d() {}
     }

预编译完成,开始执行。因为代码执行是从上到下,所以第一个console.log(a); 输出结果是function a(){},再往下执行,a又被赋值为123,再console.log(a); ,所以这边输出的是123,此时运行到第4行,第5行并不是执行语句,所以接着往下走,第6行也是console.log(a); 所以输出还是123,第7行前一半是声明,后一半才是执行语句,所以b被赋值为了function b(){},第8行是console.log(b);所以输出是function(){},再往下走,第9行不是执行语句,再走,第10句将a的值赋给d,所以此时d的值变成了123,第11行是console.log(d); 所以输出结果是123。所以四个输出结果分别是function a(){},123,123,function b(){},123。

当变量声明不写关键字时,默认为全局变量,被当成全局变量来用,但这只是一个特例(陷阱),编译器认死理,没声明变量就不是变量

预编译发生在全局

方法

  1. 创建GO对象 (Global Object)(GO 和 AO 对于编译器来说没有区别都是对象,这样取名只是方便我们区别)
  2. 找变量声明,将变量名作为GO的属性名,值赋予undefined
  3. 在全局找函数声明,将函数名作为GO对象的属性名,值赋予函数体

例子:

javascript 复制代码
    global = 100
    function fn() {
      console.log(global);
      global = 200
      console.log(global);
      var global = 300
    }
    fn()
    var global
  1. 创建GO对象 (Global Object)

    ini 复制代码
     GO = {
     
     }
     
  2. 找变量声明,将变量名作为GO的属性名,值赋予undefined

    ini 复制代码
     (这个代码存在声明提升)
     GO = {
         global : undefined
     }
  3. 在全局找函数声明,将函数名作为GO对象的属性名,值赋予函数体

    javascript 复制代码
     GO = {
         global : undefined
         fn: function fn(){}
     }

全局预编译完成了,开始执行,第1行代码给global赋值为100,之后执行到第8行,需要调用这个函数,那就又开始进行函数体预编译,步骤按照预编译在函数体的方法走。下面是最后输出结果

相关推荐
程序员大阳11 小时前
副队长JavaScript教程(50)-DOM:网页开发的起点
javascript·dom·es·节点·概念·document·关系
香芋芋圆15 小时前
iD-editor 详解|OSM官方在线编辑器,基于D3.js的轻量地图编辑器
开发语言·javascript·编辑器
晗夜未央17 小时前
任务队列反复失败,先分清重试、阻塞和结果待核对
开发语言·javascript
jktantan18 小时前
每个节点 41 字节:把一棵百万节点树拆进 14 个 typed array
前端·javascript·vue.js·算法·typescript
我命由我1234519 小时前
访客系统形式(有用户概念、无用户概念)
java·开发语言·前端·javascript·python·产品运营·产品经理
程序员大阳19 小时前
副队长JavaScript教程(65)-详解JSON:轻量级数据交换格式
javascript·json·序列化·反序列化·stringify·parse
paopaokaka_luck21 小时前
基于springboot+vue的益暖微光公益服务平台(DeepSeek公益助手、善款信息追溯、志愿服务积分闭环、ECharts运营分析、活动状态自动流转)
java·前端·javascript·spring boot·mysql·架构·echarts
栀椩21 小时前
Electron 内嵌页面跨域问题(CORS/PNA)解决全记录
前端·javascript·electron
SEO_juper21 小时前
Chrome 扩展一键查看当前页面 SEO 信息:不用切页面,点一下全出来
前端·javascript·chrome
Highcharts.js21 小时前
CSUN 2026|Highcharts无障碍数据与AI分享
javascript·人工智能·数据分析·highcharts·图表开发