一道JS前端闭包面试题解析

yizhihongxing

下面我来为你讲解一道 JS 前端闭包面试题的完整攻略。

面试题

下面是面试题的题目与内容:

for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 0);
}

要求输出 0, 1, 2, 3, 4,但是实际上却是输出了 5, 5, 5, 5, 5。请问这是为什么?如何解决这个问题?

攻略

问题的原因

首先,这个问题的原因是因为 setTimeout 函数是异步执行的,也就是说,当它被调用时,会在执行堆栈中注册一个任务,但是不会马上执行。等到当前任务执行完成之后,才会去执行相应的任务。所以在上面的示例中,五个 setTimeout 都被提交到了执行堆栈中,但是它们都是在同一个作用域里面的,也就是说它们共用了同一个变量 i

当执行完毕 for 循环后,i 的值变成了 5。然后,在执行异步任务的时候,它们都读取了作用域中的 i,而此时 i 的值已经变成了 5。所以最终输出的结果都是 5。

解决方案

为了避免上述问题,我们可以使用 JavaScript 中的闭包来解决。闭包是指有权访问另一个函数作用域中变量的函数。在上述示例中,我们可以将 setTimeout 中的函数改为一个闭包,将 i 的值传递给闭包,以此保存 i 的值,避免它们共用同一个变量。代码示例如下所示:

for (var i = 0; i < 5; i++) {
    (function(j) {
        setTimeout(function() {
            console.log(j);
        }, 0);
    })(i);
}

在这个示例中,我们使用了一个立即执行的匿名函数来创建了一个新的作用域,其中 j 的值会被赋值为 i 的值,然后将它作为参数传递给了闭包函数。这样就可以每次循环都创建一个新的作用域,避免 i 变量的共用,输出结果就会变成 0, 1, 2, 3, 4。

示例解析

下面再给两个示例来加深一下大家的理解。

示例一

for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, i * 1000);
}

这个示例中,每次循环的时候,setTimeout 的延迟时间都是 i * 1000 毫秒,也就是说每个异步任务的执行时间都是不同的。但是最终输出的结果却是 5 个 5,而不是分别输出 0, 1, 2, 3, 4。

出现这个问题的原因就是因为变量 isetTimeout 的回调函数中被共享了,它们都指向了同一个变量。因为这个问题可以使用闭包来解决,我们来看一下代码示例:

for (var i = 0; i < 5; i++) {
    (function(j) {
        setTimeout(function() {
            console.log(j);
        }, j * 1000);
    })(i);
}

在这个示例中,我们将变量 i 传递给了匿名闭包,避免了它们共享同一个作用域,这样就能够分别输出 0, 1, 2, 3, 4 了。

示例二

for (let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, i * 1000);
}

在这个示例中,我们使用了 ES6 的 let 关键字,而不是 var。由于 let 会在每次循环时创建一个新的块级作用域,所以 i 的值不会被共享。因此示例中的代码就不需要使用闭包了,可以直接输出 0, 1, 2, 3, 4。

总结

本文中,我们讲解了一道 JS 前端闭包面试题的解题思路,介绍了问题产生的原因,并给出了使用闭包和使用 let 关键字的两种解决方案。希望本文能够帮助读者更好地理解闭包的概念,并能够在实际开发中正确地使用它。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一道JS前端闭包面试题解析 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • C++使用一个栈实现另一个栈的排序算法示例

    C++使用一个栈实现另一个栈的排序算法 本文将介绍如何使用一个栈(以下称为stack1)将另一个未排序的栈(以下称为stack2)进行排序,排序结果存放在stack2中。 实现思路 我们可以通过stack1不断从stack2中弹出元素,将弹出的元素插入到正确的位置,实现栈的排序。 具体步骤如下: 创建一个临时变量temp,用于存储stack1中弹出的元素。 …

    算法与数据结构 2023年5月19日
    00
  • Javascript中的常见排序算法

    Javascript中的常见排序算法 在Javascript中,排序算法是非常基础和常见的算法之一,也是大多数编程语言都会涉及到的一部分。在实际应用场景中,常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。 冒泡排序 冒泡排序是一种简单易懂的排序算法,其中每一趟都按照从前往后的顺序比较两个相邻的元素,如果前一个元素大于后一个元素,则交换这…

    算法与数据结构 2023年5月19日
    00
  • JS中多层次排序算法的实现代码

    让我为你介绍一份JS中多层次排序算法的实现代码攻略。 简介 多层次排序是指一个列表需要依据不同的规则进行排序,例如按照价格、销量、评分等进行排序。在JS中,我们可以通过自定义排序函数实现多层次排序。 实现 以下是实现多层次排序的示例代码: const products = [ { name: ‘iPhone 11’, price: 799, sales: 1…

    算法与数据结构 2023年5月19日
    00
  • Java中的数组排序方式(快速排序、冒泡排序、选择排序)

    下面是Java中的数组排序方式的完整攻略。 1. 快速排序 快速排序是常用的一种排序算法,其时间复杂度为O(nlogn)。其基本思想是选择一个基准数,将数组分成左右两部分,比基准数小的放在左边,比基准数大的放在右边,然后再对左右两部分分别递归地进行快速排序。 Java中快速排序的实现基于Arrays类的sort方法。下面是一个示例代码: public sta…

    算法与数据结构 2023年5月19日
    00
  • python中的插入排序的简单用法

    下面是Python中插入排序的简单用法攻略: 1. 什么是插入排序 插入排序是一种简单的排序算法,它的基本思想是将未排序的元素依次插入到已排序的有序序列中的合适位置,以此完成排序。插入排序的时间复杂度为O(n^2),通常用于小规模数据的排序。 2. 插入排序的Python实现 以下是插入排序的Python代码实现: def insertion_sort(da…

    算法与数据结构 2023年5月19日
    00
  • Java桶排序之基数排序详解

    Java桶排序之基数排序详解 基本概念 基数排序(Radix Sort),又称桶排法(Bucket Sort),是一种非比较型整数排序算法。其思想是将一个数字序列拆分成多个数字进行比较排序,从个位开始,逐层进行排序,直到最高位排序完成。 实现步骤 初始化10个桶,代表数字0到9; 按照从低位到高位的顺序进行排序,首先比较个位,然后比较十位,以此类推,直到最高…

    算法与数据结构 2023年5月19日
    00
  • 算法系列15天速成 第一天 七大经典排序【上】

    我会为你详细讲解“算法系列15天速成 第一天 七大经典排序【上】”的完整攻略。 标题 算法系列15天速成 第一天 七大经典排序【上】 内容 本文主要介绍了常用的七大经典排序算法,分别是插入排序、希尔排序、选择排序、冒泡排序、快速排序、归并排序以及堆排序。对每个算法的特点、实现过程和时间复杂度进行了详细的讲解,同时也对每个算法进行了简单的示例说明。 插入排序 …

    算法与数据结构 2023年5月19日
    00
  • 希尔排序算法的C语言实现示例

    下面是“希尔排序算法的C语言实现示例”完整攻略。 希尔排序算法简介 希尔排序是通过将整个待排序数组分割成多个子序列,对每个子序列进行插入排序,然后逐步减少子序列长度,最终使整个序列有序的一种算法。 希尔排序算法的流程 按照一定的间隔将待排序数组分成若干个子序列; 对每个子序列进行插入排序,使其中的元素可以快速有序; 缩小排序间隔,重复执行步骤1和2; 直至排…

    算法与数据结构 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部