跳到主要内容
← 返回文章列表
面试题-基础2026/08/09约 3 分钟读完

面试题:闭包与状态隔离

基础面试题,考察闭包相关概念

面试题:闭包与状态隔离
文章目录 6

题目

下面代码的输出结果是什么?请解释原因。

function createCounter() {
  let count = 0;

  return function () {
    count++;
    return count;
  };
}

const counterA = createCounter();
const counterB = createCounter();

console.log(counterA());
console.log(counterA());
console.log(counterB());
console.log(counterA());

回答三个问题:

  1. 最终输出顺序是什么?

  2. createCounter() 执行结束后,为什么 count 没有被销毁?

  3. counterA 和 counterB 为什么不会互相影响?

我的回答

  1. 1 2 1 3

  2. 因为闭包的特性,它可以访问外部作用域的变量,并持久化它的引用链

  3. 它们属于不同的对象,不同的作用域

解答

回答基本正确,评分:8.5/10。

正确点:

  • 输出顺序完全正确:1 2 1 3。

  • 正确认识到返回函数可以继续访问外层的 count。

  • 正确认识到两个计数器拥有独立状态。

需要更精确的地方:

  1. “持久化引用链”表达不够准确

更标准的说法是:

createCounter() 返回的函数引用了其词法环境中的 count。只要这个返回函数仍然可达,该词法环境就不能被垃圾回收。

并不意味着变量一定会永久存在。没有引用后,闭包和相关变量仍然可以被回收。

  1. 不是因为“属于不同对象”

核心原因是:createCounter() 每调用一次,都会创建一个新的和新的 count:

counterA → 闭包 A → count A
counterB → 闭包 B → count B

两个返回函数分别引用不同的 count,所以互不影响。

面试标准表达:

最终输出 1、2、1、3。每次调用 createCounter 都会创建独立的词法环境,返回的函数形成闭包并引用其中的 count。只要返回函数仍然存在,count 就不会被垃圾回收。counterA 和 counterB 来自两次不同调用,因此分别保存独立的 count。

追问:

let counterA = createCounter();
counterA();
counterA = null;

执行 counterA = null 后,原来的 count 是否可以被垃圾回收?为什么?

追问解答

counterA = null 后,如果没有其他引用指向原来的闭包,count 就可以被垃圾回收。

原因是:

let counterA = createCounter();
counterA();        // counterA 指向返回的函数
counterA = null;   // 解除对返回函数的引用

引用关系发生了变化:

赋值前:
counterA → 返回函数 → 词法环境 → count

赋值后:
counterA → null

原返回函数 → 不再可达
词法环境   → 不再可达
count      → 可以被垃圾回收

需要纠正两个关键点。

1. null 不是对象

null 是 JavaScript 的基本类型值。虽然:

typeof null === 'object';

结果是 true,但这是 JavaScript 早期设计遗留的问题,不能据此认为 null 真的是对象。

判断 null 应该使用:

value === null

2. “可以回收”不等于“立即回收”

执行:

counterA = null;

只是让原来的函数和词法环境变成不可达状态。垃圾回收器什么时候真正释放内存,由 JavaScript 引擎决定。

标准回答:

counterA = null 解除了变量对闭包函数的引用。如果没有其他地方继续引用该函数,那么函数及其捕获的词法环境都会变得不可达,count 也就可以被垃圾回收。null 是基本类型,typeof null === 'object' 只是历史遗留问题。

评论

0 条

评论会在审核后展示,邮箱不会公开。

正在确认登录状态

5000 / 5000