当前位置: 首页 > news >正文

深度解析JavaScript面试热点:事件循环、上下文、箭头函数、变量作用域与ES6模块

JavaScript面试中经常涉及到事件循环、上下文、箭头函数、变量作用域以及ES6模块等核心概念。通过清晰的代码示例,我们深入讨论这些主题,揭示其中的关键细节。

事件循环(Event Loop)

JavaScript开发者每天都与事件循环打交道,本文通过实际代码展示了 setTimeoutPromise 和同步代码之间的交互。通过分析回应,我们纠正了一些开发者对于Promise构造函数中执行器函数同步调用的错误观念,同时详细讨论了微任务队列和宏任务队列的执行顺序。

setTimeout(() => console.log(1), 0);console.log(2);new Promise(res => {console.log(3);res();
}).then(() => console.log(4));console.log(5);
// 输出结果:2 3 5 4 1

在这个例子中,我们看到了 setTimeout、Promise 以及一些同步代码。

给定0延迟,我们传递给setTimeout的函数会同步调用还是异步调用?

  • 尽管setTimeout函数有零延迟,回调函数是异步调用的。引擎会将回调函数放在回调队列(宏任务队列)中,并在调用栈为空时将其移至调用栈。因此,数字 1 将被跳过,数字 2 将首先在控制台中显示。

我们作为参数传递给 Promise 构造函数的函数会同步调用还是异步调用?

  • Promise 构造函数接受的函数参数是同步执行的。因此,在控制台中接下来要显示的数字是 3。给定零延迟,我们传递给 promisethen 处理程序的函数会同步调用还是异步调用?

  • then方法中的回调是异步执行的,即使promise没有延迟就解决了。与setTimeout不同的是,引擎会将 promise 回调放在另一个队列中 —— 工作队列(微任务队列),在那里它将等待执行。因此,接下来进入控制台的数字是 5

哪个优先级更高 —— 微任务队列还是宏任务队列,换句话说 —— Promise 还是 setTimeout?

  • 微任务(Promise)比宏任务(setTimeout)有更高的优先级,所以下一个在控制台中的数字将是4,最后一个是1

通过分析回应,我们可以得出结论,大多数受访者在假设传递给 Promise 构造函数作为参数的执行器函数是异步调用的方面是错误的。

上下文(Context)

在面试中,对于 this 关键字的理解至关重要。我们通过具体的例子讨论了普通函数和箭头函数中 this 的不同行为,并解释了在不同上下文中函数调用的结果。

普通函数
'use strict';function foo() {console.log(this);
}function callFoo(fn) {fn();
}let obj = { foo };callFoo(obj.foo);
// 输出结果:undefined
箭头函数

深入研究了箭头函数内部的 this 值,展示了它与普通函数之间的差异。通过实例强调箭头函数不能作为构造函数使用的限制,以及它们在原型属性上的行为。

'use strict';
var x = 5;
var y = 5;function Operations(op1 = x, op2 = y) {this.x = op1;this.y = op2;
};Operations.prototype.sum = () => this.x + this.y;const op = new Operations(10, 20);console.log(op.sum());
// 输出结果:10

箭头函数没有自己的 this。相反,箭头函数体内的 this 指向该箭头函数定义所在作用域的this 值。

我们的函数是在全局作用域中定义的。

全局作用域中的 this 指向全局对象(即使在严格模式下也是如此)。因此,答案是 10

另一个关于箭头函数的问题可能是这样的。

const Num = () => {this.getNum = () => 10;
}Num.prototype.getNum = () => 20;const num = new Num();console.log(num.getNum());

箭头函数不能用作构造函数,当使用 new 调用时会抛出错误。它们也没有原型属性:

TypeError:无法设置undefined的属性(设置'getNum')

这样的问题比较少见,但你应该为它们做好准备。你可以在 MDN 上查看更多关于箭头函数的信息。

变量作用域

通过临时死区、变量声明提升等概念,详细探讨了变量作用域。通过具体的代码案例,让读者更好地理解在不同作用域中变量的行为。

'use strict';console.log(foo());let bar = 'bar';function foo() {return bar;
}bar = 'baz';
// 输出结果:ReferenceError: bar is not defined

let / const变量定义之前的作用域中的位置被称为临时死区。

如果我们在 let / const 变量定义之前尝试访问它们,将会抛出引用错误。

这种行为是因为 const 变量而被选中的。访问未定义的 var 变量时,我们得到的是undefined。对于 const 变量来说,这是不可接受的,因为它将不再是一个常量。

let 变量的行为以类似的方式完成,以便您可以轻松地在这两种类型的变量之间切换。

回到我们的例子。

由于函数调用在 bar 变量的定义之上,该变量处于临时死区。

代码抛出一个错误:

ReferenceError:初始化前不能访问'bar'

let func = function foo() {return 'hello';
}console.log(typeof foo);

在命名函数表达式中,名称只在函数体内部是局部的,外部无法访问。因此,全局作用域中不存在foo

typeof运算符对未定义的变量返回undefined

function foo(bar, getBar = () => bar) {var bar = 10;console.log(getBar());
}foo(5);

对于具有复杂参数(解构、默认值)的函数,参数列表被封闭在其自己的作用域内。

因此,在函数体中创建 bar 变量不会影响参数列表中同名的变量,getBar() 函数通过闭包从其参数中获取 bar。

一般来说,我们注意到尽管ES6已经发布了7年多,但开发人员对其特性的理解仍然很差。当然,每个人都知道这个版本中特性的语法,但只有少数人能更深入地理解它。

ES6模块

对ES6模块的导入机制进行了解析,强调了导入会被提升的特性。通过示例,展示了模块间依赖的加载顺序。

console.log('index.js');import { sum } from './helper.js';console.log(sum(1, 2));
// 输出结果:helper.js index.js 3

导入会被提升。

提升是JS中的一种机制,其中变量和函数声明在代码执行之前被移动到它们的作用域的顶部。

所有依赖项将在代码运行之前加载。

所以,答案是:helper.js index.js 3

'use strict';var num = 8;function num() {return 10;
}console.log(num);

函数和变量声明被放在其作用域的顶部,变量的初始化发生在脚本执行时。

具有相同名称的变量的重复声明将被跳过。

函数总是首先被提升。无论函数和具有相同名称的变量的声明在代码中以何种顺序出现,函数都优先,因为它上升得更高。

示例1

function num() {}
var num;
console.log(typeof num); // function

示例2

var num;
function num() {}
console.log(typeof num); // function

变量总是在最后被初始化。

var num = 8; function num() {}

将被转换为:

function num() {}
var num; // repeated declaration is ignored
num = 8;

结果,num = 8。

提高难度

import foo from './module.mjs';console.log(typeof foo);-------------------------
foo = 25;export default function foo() {}

结果export default function foo() {}

等于

function foo() {}
export { foo as default }

在引擎处理完模块代码后,你可以将其想象成以下形式:

function foo() {}
foo = 25;
export { foo as default }

所以正确答案是数字。

Promises

最后,通过一个Promise链的例子,深入讨论了Promise的执行过程,特别是在抛出错误和使用 catch 处理程序时的执行流程。

Promise.resolve(1).then(x => { throw x }).then(x => console.log(`then ${x}`)).catch(err => console.log(`error ${err}`)).then(() => Promise.resolve(2)).catch(err => console.log(`error ${err}`)).then(x => console.log(`then ${x}`));
// 输出结果:error 1 then 2

这篇文章通过清晰的代码示例和深度解析,为读者提供了深入理解JavaScript核心概念的机会,是面试前的必读材料。

相关文章:

深度解析JavaScript面试热点:事件循环、上下文、箭头函数、变量作用域与ES6模块

JavaScript面试中经常涉及到事件循环、上下文、箭头函数、变量作用域以及ES6模块等核心概念。通过清晰的代码示例,我们深入讨论这些主题,揭示其中的关键细节。 事件循环(Event Loop) JavaScript开发者每天都与事件循环打交道&am…...

Javaweb之Mybatis的动态SQL的详细解析

3. Mybatis动态SQL 3.1 什么是动态SQL 在页面原型中,列表上方的条件是动态的,是可以不传递的,也可以只传递其中的1个或者2个或者全部。 而在我们刚才编写的SQL语句中,我们会看到,我们将三个条件直接写死了。 如果页面…...

物联网与智能家居:跨境电商与未来生活的融合

物联网(Internet of Things,IoT)和智能家居技术正迅速崛起,成为跨境电商领域的创新引擎。这两者的巧妙结合不仅为消费者提供更智能、便捷的生活方式,同时也为电商平台和制造商带来了全新的商机。本文将深入探讨物联网与…...

Java内存模型(JMM)是基于多线程的吗

Java内存模型(JMM)是基于多线程的吗 这个问题按我的思路转换了下,其实就是在问:为什么需要Java内存模型 总结起来可以由几个角度来看待「可见性」、「有序性」和「原子性」 面试官:今天想跟你聊聊Java内存模型&#…...

Linux离线安装MySQL(rpm)

目录 下载安装包安装MySQL检测安装结果服务启停MySQL用户设置 下载安装包 下载地址:https://downloads.mysql.com/archives/community/ 下载全量包如:(mysql-8.1.0-1.el7.x86_64.rpm-bundle.tar) 解压:tar -xzvf mysql-8.1.0-1.el7.x86_64.…...

用 Socket.D 替代原生 WebSocket 做前端开发

socket.d.js 是基于 websocket 包装的 socket.d 协议的实现。就是用 ws 传输数据,但功能更强大。 功能原生 websocketsocket.d说明listen有有监听消息send有有发消息sendAndRequest无有发消息并接收一个响应(类似于 http)sendAndSubscribe无…...

Transformer架构和对照代码详解

1、英文架构图 下面图中展示了Transformer的英文架构,英文架构中的模块名称和具体代码一一对应,方便大家对照代码、理解和使用。 2、编码器 2.1 编码器介绍 从宏观⻆度来看,Transformer的编码器是由多个相同的层叠加⽽ 成的,每个…...

大数的乘法

题目描述 求两个不超过100位的非负整数的乘积。 输入 有两行,每行是一个不超过100位的非负整数,没有多余的前导0。 输出 一行,相乘后的结果。 样例输入 Copy 123456789 123456789样例输出 Copy 15241578750190521 代码实现&#xff1…...

年度征文 | 机器学习之心的2023

机器学习之心的2023 2023是极其复杂的一年。 生活上,养了很多宠物。 工作上,写了不少博客。 虽然遇见更多让人不开心的事情,但总体还是美好的。 愿大家新的一年健康平安,生活幸福! 机器学习是一项庞大的工程&#xff0…...

13.Kubernetes应用部署完整流程:从Dockerfile到Ingress发布完整流程

本文以一个简单的Go应用Demo来演示Kubernetes应用部署的完整流程 1、Dockerfile多阶段构建 Dockerfile多阶段构建 [root@docker github]# git clone https://gitee.com/yxydde/http-dump.git [root@docker github]# cd http-dump/ [root@docker http-dump]# cat Dockerfile …...

多年后再用TB,谈项目管理工具

背景 最近启动一个小项目,多年未曾使用项目管理工具,依稀记得使用过Basecamp,Tower,worktitle,teambition等等,当然还有mantis,vs project等等。于是随便翻阅找个用,不小心翻了TB的牌子,竟然已是阿里旗下的…...

Spark MLlib ----- ALS算法

补充 在谈ALS(Alternating Least Squares)之前首先来谈谈LS,即最小二乘法。LS算法是ALS的基础,是一种数优化技术,也是一种常用的机器学习算法,他通过最小化误差平方和寻找数据的最佳匹配,利用最小二乘法寻找最优的未知数据,保证求的数据与已知的数据误差最小。LS也被用…...

ubuntu桥接方式上网

vmvare:VMware Workstation 17 Pro ubuntu: Ubuntu 14.04.6 LTS window10 下面是我的电脑配置 下面是ubuntu虚拟机的配置 vi /etc/network/interfaces 下面的gateway就是window -ipconfig 截图里的默认网关 auto lo iface lo inet loopbackauto eth0 iface eth0 inet stat…...

收到的字符串写入xml并且将这个xml写入.zip文件中

文章目录 1、将数据写入xml文件WriteToXmlFile2、将xml文件写入zip压缩文件AddToZip3、组合起来4、使用到的头文件和动态库 1、将数据写入xml文件WriteToXmlFile void CSMSLoginDlg::WriteToXmlFile(const std::string& responseData, const std::string& xmlFileName…...

【读书笔记】《白帽子讲web安全》跨站脚本攻击

目录 前言: 第二篇 客户端脚本安全 第3章 跨站脚本攻击(XSS) 3.1XSS简介 3.2XSS攻击进阶 3.2.1初探XSS Payload 3.2.2强大的XSS Payload 3.2.2.1 构造GET与POST请求 3.2.2.2XSS钓鱼 3.2.2.3识别用户浏览器 3.2.2.4识别用户安装的软…...

第九节 初始化项目

系列文章目录 目录 系列文章目录 前言 操作方法 总结 前言 初始化项目,导入默认reset.scss 、variables.scss及mixins.scss等并修改main.js引入样式 操作方法 将默认样式表文件导入到项目。样式文件已经放到资源里请自行下载(...

【论文阅读】深度学习中的后门攻击综述

深度学习中的后门攻击综述 1.深度学习模型三种攻击范式1.1.对抗样本攻击1.2.数据投毒攻击1.3.后门攻击 2.后门攻击特点3.常用术语和标记4.常用评估指标5.攻击设置5.1.触发器5.1.1.触发器属性5.1.2.触发器类型5.1.3.攻击类型 5.2.目标类别5.3.训练方式 1.深度学习模型三种攻击范…...

Spring Boot中加@Async和不加@Async有什么区别?设置核心线程数、设置最大线程数、设置队列容量是什么意思?

在 Spring 中,Async 注解用于将方法标记为异步执行的方法。当使用 Async 注解时,该方法将在单独的线程中执行,而不会阻塞当前线程。这使得方法可以在后台执行,而不会影响主线程的执行。 在您提供的代码示例中,a1() 和…...

Vue_00001_CLI

初始化脚手架 初始化脚手架步骤: 第一步(仅第一次执行):全局安装vue/cli。 命令:npm install -g vue/cli 第二步:切换到要创建项目的目录,然后使用命令创建项目。 命令:vue creat…...

kubernetes ResourceQuotas Limits(资源配额)

开头语 写在前面:如有问题,以你为准, 目前24年应届生,各位大佬轻喷,部分资料与图片来自网络 内容较长,页面右上角目录方便跳转 简介 当多个用户或团队共享具有固定节点数目的集群时,人们会…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

生成 Git SSH 证书

🔑 1. ​​生成 SSH 密钥对​​ 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​: -t rsa&#x…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

GitHub 趋势日报 (2025年06月08日)

📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

Android15默认授权浮窗权限

我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息&#xff0…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...