JavaScript中最常见的三个面试题解析
发布时间 - 2026-01-10 23:25:33 点击率:次前言

本文不是讲述最新的JavaScript库,日常的开发实践或任何新的 ES6 函数。 相反,在讨论JavaScript时,经常会在面试中出现这3个问题。 我自己被问到过这些问题,我的朋友告诉我他们也被到问过。
当然,你在JavaScript面试前不应该只学习这3个问题 – 这里有很多 方法 可以让你更好地准备即将到来的面试 – 但面试官可能会问到下面是3个问题,来判断你对JavaScript语言的理解和DOM的掌握程度。
让我们开始吧!请注意,我们将在下面的示例中使用原生 JavaScript,因为你的面试官通常想看看你在没有第三方库(比如jQuery)的帮助下,是如何理解 JavaScript 和 DOM 的。
问题 #1: 事件委托
注:也叫事件委派,时间代理等;
当构建应用程序时,有时你需要将事件监听器绑定到页面上的按钮,文本或图像上,以便在用户与元素交互时执行某些操作。
如果我们以一个简单的待办事项列表为例,面试官可能会告诉你,他们希望在用户单击其中一个列表项时需要执行某些操作。
他们希望你用 JavaScript 实现这个功能,假设HTML代码如下:
<ul id="todo-app"> <li class="item">Walk the dog</li> <li class="item">Pay bills</li> <li class="item">Make dinner</li> <li class="item">Code for one hour</li> </ul>
你可能会想像下面这样在元素绑定事件监听器:
document.addEventListener('DOMContentLoaded', function() {
let app = document.getElementById('todo-app');
let items = app.getElementsByClassName('item');
// 将事件侦听器绑定到每个列表项
for (let item of items) {
item.addEventListener('click', function() {
alert('you clicked on item: ' + item.innerHTML);
});
}
});
虽然这个实现了功能,问题是您要单独将事件侦听器绑定到每个列表项。这是4个元素,没什么大问题,但如果有人在他们的待办事项列表中添加了10,000个事项(他们可能有很多事情要做)怎么办?然后你的函数将创建 10,000 个独立的事件监听器,并将每个事件监听器绑定到 DOM 。这样代码执行的效率非常低下。
在面试中,最好首先询问面试官用户可以输入事项的最大数量是多少。如果它永远不会超过 10 个,上面的代码将工作正常。但是,如果用户可以输入的事项数量没有限制,那么你应该使用一个更高效的解决方案。
如果你的应用程序最终可能有几百个事件监听器,更高效的解决方案是将一个事件侦听器实际绑定到整个容器上,然后在实际单击时可以访问每个确切元素。这被称为事件委托,并且它每个元素单独绑定事件处理程序更高效。
用事件委托的代码:
document.addEventListener('DOMContentLoaded', function() {
let app = document.getElementById('todo-app');
// 事件侦听器绑定到整个容器上
app.addEventListener('click', function(e) {
if (e.target && e.target.nodeName === 'LI') {
let item = e.target;
alert('you clicked on item: ' + item.innerHTML);
}
});
});
问题 #2: 在循环内使用闭包(Closures)
闭包常常在面试中出现,以便面试官衡量你对这门语言的熟悉程度,以及是否知道何时使用闭包。
闭包的本质是一个内部函数访问其作用域之外的变量。闭包可以用于实现诸如 私有变量 和 创建工厂函数之类的东西。关于使用闭包的常见面试问题是这样的:
编写一个函数,它将循环遍历整数列表,并在3秒延迟后打印每个元素的索引。
我看到这个问题的最常见(但是不正确)是像下面这样的实现:
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log('The index of this number is: ' + i);
}, 3000);
}
如果运行上面代码,3秒延迟后你会看到,实际上每次打印输出是4,而不是期望的0,1,2,3 。
为了正确理解为什么会发生这种情况,在JavaScript中很有用,这正是面试官真正的意图。
其原因是因为 setTimeout 函数创建了一个可以访问其外部作用域的函数(也就是我们经常说的闭包),每个循环都包含了索引i。
3秒后,该函数被执行并且打印出i的值,其在循环结束时为4,因为它的循环周期经历了0,1,2,3,4,并且循环最终在4时停止。
实际有几种 正确的写法来解决这个问题,下面列举两种:
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
// 通过传递变量 i
// 在每个函数中都可以获取到正确的索引
setTimeout(function(i_local) {
return function() {
console.log('The index of this number is: ' + i_local);
}
}(i), 3000);
}
const arr = [10, 12, 15, 21];
for (let i = 0; i < arr.length; i++) {
// 使用ES6的let语法,它会创建一个新的绑定
// 每个方法都是被单独调用的
// 更多详细信息请阅读: http://exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads
setTimeout(function() {
console.log('The index of this number is: ' + i);
}, 3000);
}
问题 #3: 函数防抖动(Debouncing)
有一些浏览器事件可以在很短的时间内快速启动多次,例如调整窗口大小或向下滚动页面。例如,如果将事件侦听器绑定到窗口滚动事件上,并且用户继续非常快速地向下滚动页面,你的事件可能会在3秒的范围内被触发数千次。这可能会导致一些严重的性能问题。
如果你在面试中讨论构建应用程序和事件,如滚动,窗口调整大小,或键盘按下的事件时,请务必提及 函数防抖动(Debouncing) 和/或 函数节流(Throttling)来提升页面速度和性能。一个真实的案例,来自 guest post on css-tricks:
在2011年,一个问题在Twitter上被提出:当你滚动Twitter feed时,它会会变得非常慢甚至未响应。John Resig 就这个问题发布了一篇博文,它解释了直接绑定函数到scroll事件上是多么糟糕的事。
函数防抖动(Debouncing) 是解决这个问题的一种方式,通过限制需要经过的时间,直到再次调用函数。一个正确实现函数防抖的方法是:把多个函数放在一个函数里调用,隔一定时间执行一次。这里有一个使用原生JavaScript实现的例子,用到了作用域、闭包、this和定时事件:
// debounce函数用来包裹我们的事件
function debounce(fn, delay) {
// 持久化一个定时器 timer
let timer = null;
// 闭包函数可以访问 timer
return function() {
// 通过 'this' 和 'arguments'
// 获得函数的作用域和参数
let context = this;
let args = arguments;
// 如果事件被触发,清除 timer 并重新开始计时
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
}
}
当这个函数绑定在一个事件上,只有经过一段指定的时间后才会被调用。
你可以像这样去使用这个函数:
// 当用户滚动时函数会被调用
function foo() {
console.log('You are scrolling!');
}
// 在事件触发的两秒后,我们包裹在debounce中的函数才会被触发
let elem = document.getElementById('container');
elem.addEventListener('scroll', debounce(foo, 2000));
函数节流是另一个类似函数防抖的技巧,除了使用等待一段时间再调用函数的方法,函数节流还限制固定时间内只能调用一次。所以一个事件如果在100毫秒内发生10次,函数节流会每2秒调用一次函数,而不是100毫秒内全部调用。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# javascript面试题
# javascript经典面试题
# javascript必问面试题
# 13道关于JavaScript正则表达式的面试题
# 详解JS中的this、apply、call、bind(经典面试题)
# 关于javascript作用域的常见面试题分享
# 面试常见的js算法题
# 10道典型的JavaScript面试题
# 80%应聘者都不及格的JS面试题
# Javascript前端经典的面试题及答案
# 一篇文章搞定JavaScript类型转换(面试常见)
# 总结几道关于Node.js的面试问题
# 「中高级前端面试」JavaScript手写代码无敌秘籍(推荐)
# 绑定
# 面试官
# 应用程序
# 有很多
# 才会
# 你在
# 会在
# 这个问题
# 时间内
# 问题是
# 你对
# 用户可以
# 单击
# 解决这个问题
# 防抖动
# 防抖
# 而不是
# 都是
# 是一个
# 这是
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel Octane如何提升性能_使用Laravel Octane加速你的应用
百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭
Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理
uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址
linux写shell需要注意的问题(必看)
如何续费美橙建站之星域名及服务?
JS实现鼠标移上去显示图片或微信二维码
米侠浏览器网页图片不显示怎么办 米侠图片加载修复
Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践
Swift中循环语句中的转移语句 break 和 continue
VIVO手机上del键无效OnKeyListener不响应的原因及解决方法
佛山企业网站制作公司有哪些,沟通100网上服务官网?
如何用西部建站助手快速创建专业网站?
东莞专业网站制作公司有哪些,东莞招聘网站哪个好?
Laravel如何实现本地化和多语言支持?(i18n教程)
UC浏览器如何设置启动页 UC浏览器启动页设置方法
如何在阿里云ECS服务器部署织梦CMS网站?
JavaScript如何实现错误处理_try...catch如何捕获异常?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化
Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】
Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】
Laravel的.env文件有什么用_Laravel环境变量配置与管理详解
Laravel如何使用Vite进行前端资源打包?(配置示例)
JavaScript数据类型有哪些_如何准确判断一个变量的类型
使用spring连接及操作mongodb3.0实例
如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南
php打包exe后无法访问网络共享_共享权限设置方法【教程】
在centOS 7安装mysql 5.7的详细教程
C++用Dijkstra(迪杰斯特拉)算法求最短路径
Microsoft Edge如何解决网页加载问题 Edge浏览器加载问题修复
高性能网站服务器部署指南:稳定运行与安全配置优化方案
制作企业网站建设方案,怎样建设一个公司网站?
Laravel安装步骤详细教程_Laravel环境搭建指南
如何快速搭建高效WAP手机网站?
如何用虚拟主机快速搭建网站?详细步骤解析
JS弹性运动实现方法分析
如何在Tomcat中配置并部署网站项目?
如何快速搭建高效简练网站?
HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】
Android利用动画实现背景逐渐变暗
Android使用GridView实现日历的简单功能
如何为不同团队 ID 动态生成多个非值班状态按钮
网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?
Laravel队列任务超时怎么办_Laravel Queue Timeout设置详解
如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体
作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】
青岛网站建设如何选择本地服务器?
微博html5版本怎么弄发超话_超话进入入口及发帖格式要求【教程】
Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践

