面试题答案
一键面试闭包与变量声明和数据类型的关系
- 变量声明:闭包可以访问外部函数作用域中的变量,即使外部函数已经执行完毕。外部函数的变量在闭包创建时被“捕获”,只要闭包存在,这些变量就不会被垃圾回收机制回收。例如:
function outer() {
let localVar = 10;
return function inner() {
console.log(localVar);
};
}
let closure = outer();
closure(); // 输出 10
在上述代码中,inner
函数形成了闭包,它可以访问 outer
函数中的 localVar
变量,尽管 outer
函数已经执行结束。
2. 数据类型:闭包中涉及的数据类型对其行为和内存管理有影响。基本数据类型(如 number
、string
、boolean
等)在闭包中按值传递和存储。而引用数据类型(如 object
、array
)在闭包中按引用传递。这意味着,如果闭包修改了引用数据类型的值,外部函数作用域中的该引用数据类型也会被修改。例如:
function outer() {
let obj = { value: 20 };
return function inner() {
obj.value++;
console.log(obj.value);
};
}
let closure = outer();
closure(); // 输出 21
这里 obj
是引用数据类型,闭包 inner
对 obj
的修改会反映到外部函数 outer
作用域中的 obj
。
闭包访问和修改外部函数变量
闭包通过在内部函数中直接访问外部函数作用域中的变量来实现访问和修改。例如:
function counter() {
let count = 0;
return function increment() {
count++;
return count;
};
}
let myCounter = counter();
console.log(myCounter()); // 输出 1
console.log(myCounter()); // 输出 2
在 counter
函数中,increment
函数形成闭包,它可以访问并修改 count
变量。每次调用 increment
时,count
都会自增。
闭包中数据类型引发的内存问题
当闭包引用了较大的对象或数组等引用数据类型时,由于闭包会阻止这些数据被垃圾回收机制回收,如果闭包长时间存在,可能会导致内存泄漏。例如:
function outer() {
let largeArray = new Array(1000000).fill(1);
return function inner() {
return largeArray.length;
};
}
let closure = outer();
// 这里即使 outer 函数执行完毕,largeArray 由于被闭包引用,不会被回收,占用大量内存
如果 closure
长时间存在且不释放,largeArray
占用的内存就无法被回收,导致内存泄漏。
IIFE 内部 let 与 var 声明变量的作用域
- let 声明:在 IIFE 内部使用
let
声明的变量,其作用域仅限于该 IIFE 块。例如:
(function () {
let localVar = 'let 变量';
console.log(localVar); // 输出 'let 变量'
})();
console.log(localVar); // 报错,localVar 未定义
localVar
仅在 IIFE 内部有效,外部无法访问。
2. var 声明:使用 var
声明的变量,其作用域是整个函数作用域,而不是块级作用域。例如:
(function () {
var localVar = 'var 变量';
if (true) {
var localVar = '新的 var 变量';
console.log(localVar); // 输出 '新的 var 变量'
}
console.log(localVar); // 输出 '新的 var 变量'
})();
在这个 IIFE 中,var
声明的 localVar
作用域是整个函数体,在 if
块中重新声明 localVar
实际上是对同一个变量的重新赋值。而 let
声明在块级作用域内是独立的,不同块中的 let
变量可以同名且相互独立。