JavaScript预编译与执行机制深度解析

作者:异步漫步

时间:2026-10-25

浏览:361

本文深入解析JavaScript引擎的执行流程,重点阐述语法分析、预编译及解释执行三个阶段。详细剖析预编译阶段Active Object(AO)的创建过程,包括形参处理、变量声明提升及函数声明覆盖规则,并通过三个典型代码案例演示变量与函数在内存中的实际表现。

文章目录

JavaScript属于弱类型语言,与Java等需要显式编译阶段的强类型语言不同,JavaScript在执行前也存在类似的“预编译阶段”。该阶段以代码块(如<script>标签内的代码)为作用域,每遇到一个代码块都会触发预编译>执行。深入理解JavaScript引擎的这一执行机理,有助于在编写代码时理清逻辑与执行顺序。

由于JavaScript本质上是解释型语言,其执行方式表现为逐行编译并逐行执行。

JavaScript的运行过程主要包含三个步骤: 1、语法分析 2、预编译 3、解释执行

语法分析阶段,JavaScript引擎负责检查代码中是否存在语法错误;解释执行阶段则是实际运行代码。其中,预编译是最关键的环节,其核心作用是在内存中开辟空间,用于存放变量声明和函数定义。

要深入理解预编译机制,必须首先明确函数声明与变量赋值的区别。

JavaScript中主要有两种声明方式:var用于声明变量,function用于声明方法(函数)。

在预编译阶段,JavaScript对这两种声明采取了不同的处理策略。

<script>
   var a = "1";    //声明变量a
   function b() {    //声明方法b
     alert();
   }
   var c = function () { //声明变量c
     alert();
   }
 </script>

在代码块中,a和c属于变量赋值,b属于函数声明。当执行该代码块时,首先会进入预编译阶段。对于变量赋值a和c,引擎会在内存中开辟空间并指向变量名,此时其初始值被赋为undefined。

预编译(函数执行前)

预编译阶段的具体步骤如下: 1. 创建AO对象(Active Object,活动对象) 2. 查找函数形参及函数内部变量声明,将形参名及变量名作为AO对象的属性,初始值设为undefined 3. 实参与形参统一,将实参的值赋给形参 4. 查找函数声明,将函数名作为AO对象的属性,值为函数的引用

题目1:

<script>
  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() {
    }
 
    console.log(d)
  }
  fn(1)
</script>

分析:

1)、创建AO对象

AO{
 
}

2)、查找函数形参及函数内变量声明,形参名及变量名作为AO对象的属性,值为undefined

AO{
      a:undefined,
      b:undefined,
    }

3)、实参形参相统一,实参值赋给形参

AO{
     a:1,
     b:undefined,
   }

4)、查找函数声明,函数名作为AO对象的属性,值为函数引用

AO{
      a:function a() {
      },
      b:undefined,
      d:function d() {
      }
    }

变量、函数声明后代码顺序

  function fn(a) {
    var a
    var b
 
    function a() {
    }
 
    function d() {
    }
 
    console.log(a)
    a = 123
    console.log(a)
 
    console.log(a)
    b = function () {
    }
    console.log(b)
 
    console.log(d)
  }

解释执行

当执行到a=123之前时: 此时 console.log(a)打印的值为: function a() {}

AO{
    a:function a() {
    },
    b:undefined,
      d:function d() {
    }
  }

当执行到a=123时: 此时 console.log(a)打印的值为: 123 123

AO{
      a:123,
      b:undefined,
      d:function d() {
      }
    }

当执行到b = function () {}时:

此时 console.log(b)打印的值为:function () {}

console.log(d)打印的值为:function d() {}

AO{
     a:123,
     b:function () {
     },
     d:function d() {
     }
   }

浏览器执行结果:

预编译(函数执行前)

题目2:

<script>
    function test(a, b) {
      console.log(a);
      c = 0;
      var c;
      a = 3;
      b = 2;
      console.log(b);
      function b() {
      }
 
      function d() {
      }
 
      console.log(b)
    }
    test(1)
  </script>

分析:

1)、创建AO对象

AO{
  
}

2)、查找函数形参及函数内变量声明,形参名及变量名作为AO对象的属性,值为undefined

AO{
      a:undefined,
      b:undefined,
      c:undefined
    }

3)、实参形参相统一,实参值赋给形参

AO{
      a:1,
      b:undefined,
      c:undefined
    }

4)、查找函数声明,函数名作为AO对象的属性,值为函数引用

AO{
    a:1,
    b:function b() {
    },
    c:undefined,
    d:function d() {
    }
  }

变量、函数声明后代码顺序

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

解释执行

当执行到function d() {}之前时: 此时 console.log(a)打印的值为: 1

AO{
      a:1,
      b:function b() {
      },
      c:undefined,
      d:function d() {
      }
    }

当执行到b=2之前时: 此时 console.log(b)打印的值为: 2 2

AO{
      a:1,
      b:2,
      c:0,
      d:function d() {
      }
}

浏览器执行结果:

预编译(函数执行前)

题目3:

<script>
    function test(a, b) {
      console.log(a);
      console.log(b);
      var b = 234;
      console.log(b);
      a = 123;
      console.log(a);
      function a() {
      }
 
      var a;
      b = 456;
      var b = function () {
      }
      console.log(a);
      console.log(b);
    }
    test(1)
  </script>

分析:

1)、创建AO对象

AO{
   
}

2)、查找函数形参及函数内变量声明,形参名及变量名作为AO对象的属性,值为undefined

AO{
    a:undefined,
    b:undefined
  }

3)、实参形参相统一,实参值赋给形参

AO{
     a:1,
     b:undefined
   }

4)、查找函数声明,函数名作为AO对象的属性,值为函数引用

AO{
    a:function a() {
    },
   b:undefined
  }

变量、函数声明后代码顺序

function test(a, b) {
   var a;
   var b;
 
   function a() {
   }
 
   console.log(a);
   console.log(b);
   b = 234;
   console.log(b);
   a = 123;
   console.log(a);
   b = 456;
   b = function () {
   }
   console.log(a);
   console.log(b);
 }

解释执行

当执行到function a() {}时: 此时 console.log(a)打印的值为: function a() {}

console.log(b)打印的值为: undefined

AO{
    a:function a() {
    },
    b:undefined
  }

当执行到 b=234时: 此时 console.log(b)打印的值为: 234

AO{
      a:function a() {
      },
      b:234
    }

当执行到 a=123时: 此时 console.log(a)打印的值为: 123

AO{
     a:123,
     b:234
   }

当执行到 b=456 时

AO{
     a:123,
     b:456
   }

当执行到 b = function () {}时: 此时 console.log(a)打印的值为: 123

console.log(b)打印的值为: function () {}

AO{
     a:123,
     b:function () {
     }
   }

浏览器执行结果:

预编译(函数执行前)

到此这篇关于JavaScript预编译和执行过程的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章