面试题答案
一键面试1. 代码输出结果及其原因
上述代码输出结果为:
3
3
3
原因在于 var
声明的变量存在函数作用域,而非块级作用域。在 for
循环中,var i
的作用域是整个 createFunctions
函数。当循环结束后,i
的值变为 3
。每个被 push
到 result
数组中的箭头函数,在被调用时,都会访问到同一个 i
变量,此时 i
的值已经是 3
,所以打印出的都是 3
。
2. 使用 let
和 const
修改代码及其原理
使用 let
function createFunctions() {
let result = [];
for (let i = 0; i < 3; i++) {
result.push(() => console.log(i));
}
return result;
}
let functions = createFunctions();
functions.forEach(func => func());
原理:let
声明的变量具有块级作用域。在 for
循环每次迭代时,let i
都会创建一个新的块级作用域,并且每个 i
都有自己独立的副本。所以每个箭头函数捕获到的是属于自己块级作用域内的 i
,从而打印出正确的值 0
、1
、2
。
使用 const
function createFunctions() {
let result = [];
for (const i = 0; i < 3; i++) {
(function (j) {
result.push(() => console.log(j));
})(i);
}
return result;
}
let functions = createFunctions();
functions.forEach(func => func());
原理:const
声明的变量也是块级作用域,且一旦声明不能重新赋值。由于 for
循环中的 i++
会尝试对 i
重新赋值,所以这里通过立即执行函数(IIFE)创建新的作用域,将 i
作为参数传递进去,每个 IIFE 内的 j
是独立的,箭头函数捕获到的是每个独立的 j
,从而打印出正确的值 0
、1
、2
。
3. 闭包环境下作用域对内存管理和性能的潜在影响
- 函数作用域:在闭包中,如果使用函数作用域(如
var
),可能会导致变量在函数执行完后依然被引用,无法被垃圾回收机制回收,从而造成内存泄漏。因为闭包会保持对外部作用域变量的引用,如果这些变量不必要地长时间存在,会占用额外的内存。 - 块级作用域:块级作用域(如
let
和const
)能更精确地控制变量的生命周期。当块级作用域结束,其中声明的变量不再被引用时,就可以被垃圾回收机制回收,有利于更好的内存管理。在性能方面,合理使用块级作用域可以减少不必要的内存占用,提升应用程序的性能,尤其是在频繁创建和销毁闭包的场景下。