网易JS面试题与Javascript词法作用域说明

yizhihongxing

下面是关于“网易JS面试题与Javascript词法作用域说明”的完整攻略。

网易JS面试题简介

网易曾经在招聘时使用过一个著名的 JavaScript 面试题:

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

预期的输出结果应该是 0 1 2 3,但是实际的输出结果却是 4 4 4 4

原因分析

这个面试题涉及到了 JavaScript 中闭包和词法作用域的概念,其中主要涉及到了以下几个问题:

  1. JavaScript 中 setTimeout 的工作机制是什么?
  2. JavaScript 中变量作用域的工作机制是什么?

接下来我们会详细探讨这两个问题。

setTimeout 工作机制

setTimeout 实际上是一个异步操作,它会将后面的任务交给浏览器的任务队列(task queue)来执行,等到当前线程的任务全部执行完成以后,再执行队列中的任务。也就是说,setTimeout 不会造成阻塞,而是按照自己设定的时延,等到任务队列中没有待执行的任务时才执行。

例如,在上面的代码中,当我们执行到第一次调用 setTimeout 时,setTimeout 会让后面的任务推迟到下一次事件循环再执行,此时循环已经结束,变量 i 的值已经变成了 4,因此后面的 setTimeout 函数的回调都会输出 4。

词法作用域的工作机制

JavaScript 使用词法作用域(Lexical Scope)来确定一个变量的作用范围,词法作用域是静态的,它关注函数被定义的位置,而不关心它被调用的位置。

例如,在上面的代码中,var 的定义为全局作用域,而不是for循环体中的块级作用域。因此,在循环结束后,变量 i 的值被更新为了 4,而后面的 setTimeout 函数都是在全局作用域中执行,因此会认为 i 的值是 4。这样每次输出的都是 4。

版本一:使用闭包

一种解决方法是使用闭包,将变量 i 的值保存在一个闭包中,代码如下所示:

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

使用立即执行函数(IIFE)创建一个闭包,将变量 i 的值传递到闭包中,每个闭包都有自己的作用域,因此可以将当前循环的变量 i 的值保存在闭包中。这样就可以输出预期的结果。

版本二:使用 let 关键字

在 ES6 中,我们可以使用 let 关键字来声明块级作用域的变量,它的作用域仅限于当前的块级作用域,也就是说,在循环体中声明的 let 变量,在每次循环迭代时都会重新绑定一次。

for(let i = 0; i < 4; i++) {
  setTimeout(() => console.log(i), 0);
}

使用 let 定义变量 i,在每次迭代中都会重新绑定当前迭代的值,因此可以输出预期的结果。

总结

以上两种方法都可以解决这个面试题,它们都是通过将变量的作用域限制在块级作用域中来避免变量共享的问题,从而达到预期的结果。在实际应用中,我们应该优先使用 let 关键字来声明变量,这样可以避免一些诡异的行为。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:网易JS面试题与Javascript词法作用域说明 - Python技术站

(0)
上一篇 2023年6月10日
下一篇 2023年6月10日

相关文章

  • 定单管理上 JS表格排序第1/2页

    针对“定单管理上 JS表格排序第1/2页”的完整攻略,我来给你详细讲解。 首先,你需要在前端页面上加入一个表格组件,这个组件要支持排序功能。可以使用一些常见的表格插件,如jQuery DataTables、Bootstrap Table等,这些插件都自带排序功能。 接下来,你需要绑定排序事件,在用户对表格列进行排序时触发。可以在表头th标签中添加可点击的元素…

    JavaScript 2023年6月11日
    00
  • JavaScript利用时间分片实现高性能渲染数据详解

    JavaScript利用时间分片实现高性能渲染数据详解 什么是时间分片 时间分片是一项 Web API 新特性,它可以让长时间运行的 JavaScript 任务在多个时间间隔执行。在使用时间分片任务时,可以将大型任务分割为更小的任务,以便浏览器在不影响主线程性能的情况下,逐步执行它们。 为什么需要时间分片 在 JavaScript 中,如果一个任务运行时间太…

    JavaScript 2023年6月11日
    00
  • JavaScript中的ArrayBuffer详细介绍

    JavaScript中的ArrayBuffer是一种用于存储二进制数据的内存缓冲区。它提供了许多高效地操作二进制数据的方法,包括创建、读写、复制、转换等。 创建ArrayBuffer 在JavaScript中,我们可以通过以下方式来创建一个ArrayBuffer: let buffer = new ArrayBuffer(length); 其中length表…

    JavaScript 2023年5月27日
    00
  • 笛卡尔乘积介绍

    笛卡尔积介绍 笛卡尔积是一个非常常用的概念,它将两个集合中的所有元素配对,然后生成所有可能的组合。在计算机科学中,笛卡尔积是一种非常重要的技术,因为它让我们能够快速生成大量组合数据,从而用于各种计算和应用领域,比如机器学习、数据分析等。 示例说明 让我们通过两个简单的例子来说明笛卡尔积的概念: 例子 1 假设我们有两个集合 A 和 B,分别为: A = {1…

    JavaScript 2023年5月28日
    00
  • javascript动画之模拟拖拽效果篇

    下面我来详细讲解“javascript动画之模拟拖拽效果篇”的完整攻略。 简介 在前端开发中,拖拽是常见的交互效果之一,可以大大提升用户体验。本篇文章将介绍如何用javascript实现模拟拖拽效果。 实现原理 要实现拖拽效果,需要用到鼠标事件(mousedown、mousemove、mouseup),在mousedown事件中获取鼠标的坐标,然后在移动鼠标…

    JavaScript 2023年6月10日
    00
  • Javascript Date setHours() 方法

    以下是关于JavaScript Date对象的setHours()方法的完整攻略,包括两个示例说明。 JavaScript Date对象的setHours()方法 JavaScript Date对象的setHours()方法设置日期对象的小时部分。该方法接受一个整数,表示要设置的小时数。如果该参数超出了24小时制的范围,则自动调整为合法的小时数。 下面是使用…

    JavaScript 2023年5月11日
    00
  • JS中Attr的用法详解

    JS中Attr的用法详解 在JavaScript中,Attr(Attribute)指元素的特性或属性。Attr可以添加、修改和删除元素的属性。在DOM中,Attr是通过一个节点对象的attributes属性来获取和操作的。 Attr的获取 我们可以使用 getAttribute 方法获得一个指定属性的值。比如我们需要获取一个 id=”myId” 的元素的 i…

    JavaScript 2023年6月11日
    00
  • 和我一起学 Three.js【初级篇】:1. 搭建 3D 场景

    ? 本篇文章共 5572 字,最近更新于 2023 年 04 月 19 日。 0. 系列文章合集 本系列第 6,7,8 章节支持在我的个人公众号「前端乱步」内付费观看,将在全平台文章「点赞数」+「评论数」 >= 500(第 6 章), 1000(第 7,8 章) 时分别解锁发布。 《和我一起学 Three.js【初级篇】:0. 总论》 ? 您当前在这里…

    JavaScript 2023年4月20日
    00
合作推广
合作推广
分享本页
返回顶部