javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS执行上下文、调用栈及编译流程

JS执行机制之执行上下文 + 调用栈 + 编译流程(含大厂真题实战)

作者:YHL

由于JS是动态类型的语言,所以语言本身设计了很多复杂的机制,比如作用域、函数调用、this处理等等,加上其运行环境的复杂性,这篇文章主要介绍了JS执行机制之执行上下文+调用栈+编译流程的相关资料,需要的朋友可以参考下

前言:

JS 并非逐行直接执行,而是遵循 先预编译、后执行 的底层机制。执行上下文、调用栈、变量提升、块级作用域,是前端面试、笔试核心重难点,也是读懂 JS 代码执行逻辑的关键。

本文遵循 基础概念 → 底层原理 → 编译流程 → 真题实战 → 核心总结 逻辑,搭配8道大厂高频真题,从零吃透 JS 完整执行机制!

一、核心基础:执行上下文(代码运行的载体)

所有 JS 代码运行,都必须依托 执行上下文对象,该对象包含三大核心模块,分工明确、互不冲突:

1. 变量环境

存储:var 声明的变量、function 函数声明

特性:支持变量提升、函数提升,无块级作用域,是 ES5 及之前的变量存储机制。

2. 词法环境

存储:let、const 声明的变量

特性(ES6 全新机制,修复 var 所有缺陷):

3. 执行代码

JS 代码最终执行规则:从上到下、逐行顺序执行

💡 核心结论:变量环境、词法环境、执行代码,三者共同构成完整的执行上下文,支撑所有 JS 代码运行。

二、底层调度:调用栈(V8引擎执行容器)

💡 调用栈是 V8 引擎用于 管理函数调用关系、控制代码执行顺序 的栈式数据结构,所有执行上下文都由调用栈统一管理。

✅ 核心执行规则(必背):

三、核心流程:JS 预编译全过程

JS 核心机制:先编译预解析,后逐行执行,编译阶段决定变量提升、函数提升的最终结果,分为4个固定步骤:

步骤1:创建执行上下文

进入全局/函数作用域,自动生成全新执行上下文,初始化运行环境。

步骤2:扫描变量声明

遍历代码,收集所有 var 变量、函数形参,挂载到变量环境,默认赋值 undefined(变量提升原理)。

步骤3:同步形参实参(仅函数上下文)

将调用函数传入的实参值,赋值给对应形参,全局作用域无此步骤。

步骤4:扫描函数声明

收集所有 function 函数声明,整体提升存入变量环境,函数提升优先级高于变量提升

四、ES6 革新:let/const 底层机制

et、const 是为修复 var 历史 bug 诞生,核心差异在于存储环境和作用域规则:

✅ 核心特性汇总:

💡 设计意义:彻底解决 var 变量泄露、作用域混乱、重复声明、提升异常等问题。

五、大厂真题实战(8道原题吃透执行机制)

结合上面所有理论,通过笔试原题实战,彻底搞懂变量提升、作用域隔离、上下文执行规则。

案例1:基础变量提升 + 函数提升

核心考点:编译阶段提前提升声明,实现先调用后定义

// 开发者书写代码
showName('极客时间')
console.log(myname)

var myname = 'yihao'
function showName(name) {
  console.log(name);
  var b = 1;
  console.log('函数showName执行', name)
}

✅ V8 编译预处理(真实执行逻辑):

// 1. 变量提升(声明提升,值为undefined)
var myname;
// 2. 函数整体提升(完整函数体优先提升)
function showName(name) {
  console.log(name);
  var b = 1;
  console.log('函数showName执行', name)
}

// 3. 从上至下逐行执行
showName('极客时间')
console.log(myname) // 输出 undefined
myname = 'yihao'

💡 结果:先打印「极客时间」,再打印 undefined。

案例2:变量与函数提升优先级对比

核心铁律:函数提升优先级 > var 变量提升

// 原生代码
showName();
console.log(myname);
myname = 'yihao';
console.log(func);
function func() {}
var func = 1;

✅ 编译提升后逻辑:

var myname;
var func;
function showName() {
  console.log('函数showName执行');
}
// 同名函数提升覆盖变量
function func() {}

showName();
console.log(myname); // undefined
myname = 'yihao';
console.log(func); // 打印函数体
func = 1;

案例3:拼多多面试题(同名标识符冲突)

核心考点:形参、变量、同名函数的覆盖规则

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

✅ 详细解析:

案例4:var 无块级作用域(变量泄露)

核心考点:var 仅区分函数作用域,不识别 {} 块级作用域

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;
    console.log(x); // 2
  }
  console.log(x); // 2  内层变量覆盖外层,变量泄露
}
varTest();

案例5:let 块级作用域隔离

核心考点:词法环境实现块级隔离,杜绝变量泄露

function varTest() {
  var x = 1;
  if (true) {
    let x = 2;
    let b = 3;
    console.log(x); // 2 块级局部变量
  }
  // console.log(b); // 报错:b 仅块内生效
  console.log(x); // 1 外层var变量不受影响
}
varTest();

案例6:var/let 混合声明综合题

核心考点:变量环境、词法环境双重规则叠加

function foo() {
  var a = 1;
  let b = 2;
  {
    let b = 3;
    var c = 4;
    let d = 5;
    console.log(a); // 1 上层变量可穿透块级
    console.log(b); // 3 块级局部变量优先
  }
  console.log(b); // 2 外层b不受块内影响
  console.log(c); // 4 var无块级隔离,全局穿透
  // console.log(d); // 报错 d为块级私有变量
}
foo();

案例7:let 禁止重复声明规则

// let 严格禁止同作用域重复声明
let a = 1;
// let a =2; // 直接报错

// 变量与函数同名冲突
function a() {

}

案例8:综合报错+提升终极案例

// 综合测试:变量提升、重复声明、作用域冲突
// console.log(a);
// var a = 1;
// function a(){}

// let 不支持重复声明、无变量提升
let a = 1;
// let a =2;
function a() {

}

六、核心知识点对比总结

七、总结

到此这篇关于JS执行机制之执行上下文+调用栈+编译流程的文章就介绍到这了,更多相关JS执行上下文、调用栈及编译流程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文