🔥9道题穿透JS底层:堆栈/异步/执行栈连环问,第5题99%人翻车?📉

1. 数据类型分别存在哪里?

(1) var a = {name: "前端开发"}; var b = a; a = null,b输出什么?

js 复制代码
var a = {name: "前端开发"}; // a指向堆中对象地址
var b = a;                 // b复制a的地址 → 指向同一对象
a = null;                  // a被重定向为null,b仍指向原对象
console.log(b);            // {name: "前端开发"} ✅

关键点b = a地址复制,不是深拷贝。a断开连接,b不受影响。

「Q1: 如果 b.name = "改了",a再访问会怎样?❓」

A1: a已为null,但若a未被赋null,a.name也会变成"改了",因为指向同一堆对象!👉继续看?

「Q2: 什么情况下b会变null?💥」

A2: 只有 b = null 才行。或者全局作用域被销毁(如页面关闭)。

「Q3: 这种机制叫什么?🤯」

A3: 按引用传递(pass-by-reference)的错觉 ,其实是按值传递地址(call-by-sharing)。


(2) var a = {b: 1} 存放在哪里?

  • a 这个变量名:栈中
  • {b: 1} 整个对象:堆中
  • a 的值:指向堆中该对象的指针(内存地址)

ASCII示意:

css 复制代码
栈(Stack)        堆(Heap)
+-------+       +-------------+
|   a   | ----> | {b: 1}      |
+-------+       +-------------+

⚠️你以为a存的是{b:1}?不,它只存了个"门牌号"!


(3) var a = {b: {c: 1}} 存放在哪里?

js 复制代码
// 拆解:
// a → 栈
// a.b → 指向堆中另一个对象 {c: 1}
// 所以:两个对象都在堆里,嵌套 = 指针链

ASCII示意:

lua 复制代码
栈                堆
+-------+       +-------------+
|   a   | ----> | b: ──────┐  |
+-------+       +----------|--
                          ↓
                   +-------------+
                   | c: 1        |  ← 另一个堆对象
                   +-------------+

⚠️每层对象都是独立堆内存块!

「Q4: 深拷贝为什么慢?💥」

A4: 因为要递归遍历所有嵌套对象,在堆中新建副本,还要重建指针关系。

「Q5: WeakMap的key为什么只能是对象?🤯」

A5: 因为它用弱引用指向堆对象,不影响垃圾回收,基本类型无法弱引用。


2. 栈和堆的区别?

维度 栈(Stack) 堆(Heap)
管理方式 自动管理(LIFO) 手动/GC管理
速度 快(连续内存) 慢(碎片化)
生命周期 与函数执行周期绑定 动态,直到无引用
存储内容 基本类型、函数参数、局部变量、执行上下文 对象、数组、闭包环境
内存分配 编译时确定大小 运行时动态分配

「Q6: 递归太深为什么会栈溢出?💥」

A6: 每次调用函数都会在栈压入执行上下文,超出内存限制 → Maximum call stack size exceeded

「Q7: 堆内存一定比栈大吗?❓」

A7: 通常如此,但取决于引擎实现和系统资源。


3. 垃圾回收时栈和堆的区别?

  • :函数执行完自动弹出,变量自动销毁,无需GC介入 ✅
  • :需GC(如V8的分代回收)标记-清除/引用计数来回收无用对象
js 复制代码
function foo() {
  var obj = {a: 1}; // obj在栈,{a:1}在堆
}
foo(); // 函数结束 → obj出栈 → 堆中{a:1}失去引用 → 下次GC被回收

「Q8: 闭包为什么会导致内存泄漏?⚠️」

A8: 内层函数引用外层变量,外层执行完但变量仍被引用 → 堆对象无法回收!

「Q9: WeakSet如何避免内存泄漏?👉继续看?」

A9: 它的元素是弱引用,不影响GC,适合临时存储对象元数据。


4. 数组取第1个和第10万个元素时间差?

几乎无差别!O(1)

因为数组是连续内存块 ,通过基地址 + 索引 × 元素大小直接计算位置。

js 复制代码
// 伪代码
address = baseAddress + index * sizeof(element)

无论 index=0 还是 index=99999,计算一步到位。

「Q10: 什么数据结构查第n个元素是O(n)?💥」

A10: 链表!必须从头逐个遍历。

「Q11: JS数组真是连续内存吗?❓」

A11: 对密集数组(数值索引连续),V8会优化为连续存储;稀疏数组用哈希表。


5. 栈和堆具体怎么存储?

栈存储结构(函数调用栈)

sql 复制代码
+------------------+
| foo() 执行上下文  |
| - 变量对象        |
| - this           |
| - 作用域链        |
+------------------+
| bar() 上下文      |
+------------------+
| global 上下文     |
+------------------+

LIFO,函数调用即压栈,return即弹栈。

堆存储结构

  • 对象以键值对+隐藏类(Hidden Class) 存储,V8用指针指向属性位置
  • 数组可能用快速属性(in-object)或慢速字典模式

「Q12: 为什么频繁增删对象属性会变慢?🤯」

A12: 因为会破坏隐藏类,V8无法做内联缓存优化 → 回退到字典查找。


6. JS怎么实现异步?

事件循环(Event Loop) + 回调队列(Callback Queue)

graph TB A[JS引擎] --> B[调用栈] B --> C{异步API?} C -->|是| D[Web API环境: DOM, setTimeout, fetch] D --> E[任务队列: Macro/Micro] E --> F[事件循环检查调用栈] F -->|空| G[推任务进调用栈] C -->|否| B style A fill:#f9f,stroke:#333,stroke-width:2px style D fill:#bbf,stroke:#333,stroke-width:2px style E fill:#ff9,stroke:#333,stroke-width:2px style F fill:#9f9,stroke:#333,stroke-width:2px

⚡异步不是JS干的,是浏览器/Node帮它托底!

「Q13: Node和浏览器的Event Loop一样吗?💥」

A13: 不同!Node有多个阶段(timers, poll, check等),浏览器更简单。


7. 异步整个执行周期?

js 复制代码
console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);
// 输出:1 4 3 2

执行流程:

  1. 同步代码入栈执行 → 1, 4
  2. setTimeout → 丢给Web API,到期后进宏任务队列
  3. Promise.then → 进微任务队列
  4. 同步执行完 → 清空微任务(3)→ 下一轮事件循环取宏任务(2)

「Q14: 微任务一定比宏任务先执行吗?👉继续看?」

A14: 是!每轮事件循环末尾都会清空微任务队列。


8. Async/Await怎么实现?

语法糖 + Promise + 状态机

js 复制代码
async function fn() {
  const res = await fetch('/api');
  return res.json();
}
// 等价于:
function fn() {
  return Promise.resolve(fetch('/api')).then(res => {
    return res.json();
  });
}

Babel转译后本质是 generator + co 模式,自动管理Promise状态。

「Q15: await后面不是Promise会怎样?💥」

A15: 会被 Promise.resolve() 包装,立即resolve。


9. Promise和setTimeout执行先后?

js 复制代码
setTimeout(() => console.log('宏'), 0);
Promise.resolve().then(() => console.log('微'));
// 输出:微 → 宏
  • Promise.then → 微任务
  • setTimeout → 宏任务

微任务优先于宏任务执行

「Q16: 为什么要有微任务?直接都放宏任务不行吗?🤯」

A16: 为了保证异步回调能"同步"执行完,比如Promise链,避免中间被其他宏任务打断。


10. 为什么要区分微任务和宏任务?

为了执行优先级与一致性

  • 微任务:当前操作的延续(如Promise链、MutationObserver)
  • 宏任务:独立事件(如setTimeout、I/O、UI渲染)

想象你写代码:then().then().then() 应该一口气执行完,而不是被中间插入一个setTimeout打断。

「Q17: Vue的$nextTick用了哪种任务?💥」

A17: 优先微任务(Promise.then),降级为宏任务(setTimeout)。


11. Promise构造函数是同步还是异步?then呢?

js 复制代码
new Promise((resolve) => {
  console.log('构造函数立即执行'); // 立即输出
  resolve(1);
}).then(res => {
  console.log('then是异步', res); // 微任务,稍后输出
});
// 输出顺序:构造函数立即执行 → then是异步 1
  • 构造函数:同步执行
  • then回调:异步(微任务)

「Q18: catch是同步还是异步?👉继续看?」

A18: 同样是微任务,和then一样异步执行。


12. 发布-订阅 vs 观察者模式?

观察者模式(Observer) 发布-订阅(Pub-Sub)
耦合度 高(目标直接管理观察者) 低(通过事件中心解耦)
通信方式 目标 → 观察者 发布者 ⇄ 事件中心 ⇄ 订阅者
角色 Subject + Observer Publisher + Broker + Subscriber
js 复制代码
// 观察者模式
class Subject {
  observers = [];
  addObserver(o) { this.observers.push(o); }
  notify() { this.observers.forEach(o => o.update()); }
}
js 复制代码
// 发布订阅
const events = {};
on('click', handler);
emit('click'); // 遍历执行

「Q19: Vue2的响应式是哪种?💥」

A19: 观察者模式!Dep是Subject,Watcher是Observer。


13. JS执行过程分哪些阶段?

  1. 语法分析:检查代码是否合法
  2. 预编译:创建GO/AO,变量提升
  3. 执行
    • 创建执行上下文(入栈)
    • this绑定
    • 词法环境初始化
    • 代码执行
    • 上下文出栈

「Q20: let/const为什么有暂时性死区?🤯」

A20: 因为预编译时也提升,但不初始化,直到声明语句才初始化 → 中间区域访问报错。


14. 词法作用域和this的区别?

词法作用域(Lexical Scope) this(动态绑定)
确定时机 函数定义时(写代码时) 函数调用时(运行时)
决定因素 函数在哪定义 如何调用(谁调用、new、call等)
查找方式 向外层作用域链查找 根据调用方式动态绑定
js 复制代码
var name = 'window';
function foo() {
  console.log(this.name);     // 动态
  console.log(name);          // 词法:沿作用域链找
}
const obj = {name: 'obj', foo};
foo();     // window, window
obj.foo(); // obj, window(词法仍指向全局name)

「Q21: 箭头函数的this是词法作用域吗?💥」

A21: 是!箭头函数没有自己的this,继承外层函数定义时的作用域。

相关推荐
若梦plus几秒前
模块化与package.json
前端
烛阴5 分钟前
Aspect Ratio -- 宽高比
前端·webgl
若梦plus8 分钟前
Node.js中util.promisify原理分析
前端·node.js
gnip9 分钟前
滚动元素到可视区
前端·javascript
噫酱永不放弃11 分钟前
愈发简单的 JS 库开发
前端·rollup.js
若梦plus20 分钟前
Xata低代码服务器端数据库平台之技术分析
前端·后端
摆烂工程师21 分钟前
GPT-5 即将凌晨1点进行发布,免费用户可以使用 GPT-5
前端·人工智能·程序员
若梦plus23 分钟前
Xano低代码后端开发平台之技术分析
前端·后端
若梦plus27 分钟前
《深入 SystemJS:构建灵活解耦的前端模块体系》
前端
若梦plus31 分钟前
动作流执行引擎与工作流引擎
前端