MST

星途 面试题库

面试题:JavaScript中闭包与作用域链的关系

描述闭包是什么,它如何依赖作用域链工作。举例说明在实际开发场景中,闭包是怎样利用作用域链实现数据的封装和持久化的。
17.7万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

闭包的定义

闭包是指有权访问另一个函数作用域中的变量的函数。简单来说,当一个函数内部定义了另一个函数,并且内部函数可以访问外部函数的变量时,就形成了闭包。

闭包与作用域链的关系

  1. 作用域链基础:每个函数在创建时,都会生成一个作用域链(scope chain)。作用域链决定了函数在查找变量时的搜索路径。当函数执行时,它首先在自己的作用域(局部作用域)中查找变量,如果找不到,就会沿着作用域链向上,到包含它的外部函数的作用域中查找,以此类推,直到全局作用域。
  2. 闭包对作用域链的依赖:闭包函数在创建时,会将其包含函数(外部函数)的活动对象添加到自己的作用域链前端。这样,闭包函数就可以访问到外部函数作用域中的变量。即使外部函数执行完毕并返回,其活动对象在内存中也不会被销毁,因为闭包函数仍然持有对该活动对象的引用,这使得闭包能够继续访问外部函数的变量。

实际开发场景中闭包利用作用域链实现数据封装和持久化的例子

  1. 数据封装
function Counter() {
    let count = 0; // 被封装的数据
    function increment() {
        count++;
        return count;
    }
    return increment;
}
const counter = Counter();
console.log(counter()); // 输出 1
console.log(counter()); // 输出 2
// 这里外部无法直接访问count变量,实现了数据封装

在上述代码中,Counter 函数返回一个内部函数 incrementincrement 函数形成了闭包,它可以访问 Counter 函数作用域中的 count 变量。而外部代码无法直接访问 count,从而实现了数据封装。

  1. 数据持久化
function createAdder(x) {
    return function(y) {
        return x + y;
    };
}
const add5 = createAdder(5);
console.log(add5(3)); // 输出 8
console.log(add5(7)); // 输出 12

在这个例子中,createAdder 函数接受一个参数 x,并返回一个内部函数。返回的内部函数形成闭包,它记住了 createAdder 函数执行时的 x 值。无论这个内部函数在何处被调用,它都能使用这个持久化的 x 值进行计算,实现了数据的持久化。