MST

星途 面试题库

面试题:JavaScript 函数与块级作用域在闭包场景下的深度剖析

考虑如下 JavaScript 代码: ```javascript function createFunctions() { let result = []; for (var i = 0; i < 3; i++) { result.push(() => console.log(i)); } return result; } let functions = createFunctions(); functions.forEach(func => func()); ``` 1. 解释上述代码输出结果及其原因,结合函数作用域和块级作用域相关知识说明 `var` 的问题。 2. 如何修改代码使得每个函数打印出正确的 `i` 值(分别使用 `let` 和 `const` 来实现,并解释原理)。 3. 探讨在闭包环境下,函数作用域和块级作用域对内存管理和性能的潜在影响。
31.3万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

1. 代码输出结果及其原因

上述代码输出结果为:

3
3
3

原因在于 var 声明的变量存在函数作用域,而非块级作用域。在 for 循环中,var i 的作用域是整个 createFunctions 函数。当循环结束后,i 的值变为 3。每个被 pushresult 数组中的箭头函数,在被调用时,都会访问到同一个 i 变量,此时 i 的值已经是 3,所以打印出的都是 3

2. 使用 letconst 修改代码及其原理

使用 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,从而打印出正确的值 012

使用 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,从而打印出正确的值 012

3. 闭包环境下作用域对内存管理和性能的潜在影响

  • 函数作用域:在闭包中,如果使用函数作用域(如 var),可能会导致变量在函数执行完后依然被引用,无法被垃圾回收机制回收,从而造成内存泄漏。因为闭包会保持对外部作用域变量的引用,如果这些变量不必要地长时间存在,会占用额外的内存。
  • 块级作用域:块级作用域(如 letconst)能更精确地控制变量的生命周期。当块级作用域结束,其中声明的变量不再被引用时,就可以被垃圾回收机制回收,有利于更好的内存管理。在性能方面,合理使用块级作用域可以减少不必要的内存占用,提升应用程序的性能,尤其是在频繁创建和销毁闭包的场景下。