面试题答案
一键面试闭包的定义
闭包是指有权访问另一个函数作用域中的变量的函数。简单来说,当一个函数内部定义了另一个函数,并且内部函数可以访问外部函数的变量时,就形成了闭包。
闭包与作用域链的关系
- 作用域链基础:每个函数在创建时,都会生成一个作用域链(scope chain)。作用域链决定了函数在查找变量时的搜索路径。当函数执行时,它首先在自己的作用域(局部作用域)中查找变量,如果找不到,就会沿着作用域链向上,到包含它的外部函数的作用域中查找,以此类推,直到全局作用域。
- 闭包对作用域链的依赖:闭包函数在创建时,会将其包含函数(外部函数)的活动对象添加到自己的作用域链前端。这样,闭包函数就可以访问到外部函数作用域中的变量。即使外部函数执行完毕并返回,其活动对象在内存中也不会被销毁,因为闭包函数仍然持有对该活动对象的引用,这使得闭包能够继续访问外部函数的变量。
实际开发场景中闭包利用作用域链实现数据封装和持久化的例子
- 数据封装:
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
函数返回一个内部函数 increment
。increment
函数形成了闭包,它可以访问 Counter
函数作用域中的 count
变量。而外部代码无法直接访问 count
,从而实现了数据封装。
- 数据持久化:
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
值进行计算,实现了数据的持久化。