JavaScript中最常见的三个面试题解析


Posted in Javascript onMarch 04, 2017

前言

本文不是讲述最新的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 导出数据到Excel(处理table中的元素)
Dec 18 Javascript
from 表单提交返回值用post或者是get方法实现
Aug 21 Javascript
js实现的点击div区域外隐藏div区域
Jun 30 Javascript
node.js中的fs.openSync方法使用说明
Dec 17 Javascript
基于jQuery实现拖拽图标到回收站并删除功能
Nov 25 Javascript
jquery.qtip提示信息插件用法简单实例
Jun 17 Javascript
Bootstrap轮播图学习使用
Feb 10 Javascript
angular $watch 一个变量的变化(实例讲解)
Aug 02 Javascript
vue与bootstrap实现时间选择器的示例代码
Aug 26 Javascript
vue使用高德地图根据坐标定位点的实现代码
Aug 22 Javascript
浅谈Node新版本13.2.0正式支持ES Modules特性
Nov 25 Javascript
nuxt.js 在middleware(中间件)中实现路由鉴权操作
Nov 06 Javascript
jQuery插件echarts实现的多折线图效果示例【附demo源码下载】
Mar 04 #Javascript
Vue.js实现多条件筛选、搜索、排序及分页的表格功能
Nov 24 #Javascript
纯JS单页面赛车游戏制作代码分享
Mar 03 #Javascript
JS html时钟制作代码分享
Mar 03 #Javascript
AngularJS路由实现页面跳转实例
Mar 03 #Javascript
vue2笔记 — vue-router路由懒加载的实现
Mar 03 #Javascript
求js数组的最大值和最小值的四种方法
Mar 03 #Javascript
You might like
PHP写入WRITE编码为UTF8的文件的实现代码
2008/07/07 PHP
php面向对象全攻略 (八)重载新的方法
2009/09/30 PHP
PHP编写学校网站上新生注册登陆程序的实例分享
2016/03/21 PHP
关于PHP通用返回值设置方法
2017/03/31 PHP
PHP生成图表pChart的示例解析
2020/07/31 PHP
js 覆盖和重载 函数
2009/09/25 Javascript
jquery $(document).ready() 与window.onload的区别
2009/12/28 Javascript
跟着JQuery API学Jquery 之二 属性
2010/04/09 Javascript
Jquery实现的tab效果可以指定默认显示第几页
2013/10/16 Javascript
Jquery+asp.net后台数据传到前台js进行解析的方法
2014/05/11 Javascript
JavaScript实现关键字高亮功能
2014/11/12 Javascript
详解JavaScript 中getElementsByName在IE中的注意事项
2017/02/21 Javascript
Node.js学习之地址解析模块URL的使用详解
2017/09/28 Javascript
nodejs基于mssql模块连接sqlserver数据库的简单封装操作示例
2018/01/05 NodeJs
基于JavaScript实现幸运抽奖页面
2020/07/05 Javascript
[04:36]DOTA2国际邀请赛 ti3精彩集锦
2013/08/19 DOTA
[53:49]LGD vs Fnatic 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
TF-IDF算法解析与Python实现方法详解
2017/11/16 Python
python字符串string的内置方法实例详解
2018/05/14 Python
python中利用h5py模块读取h5文件中的主键方法
2018/06/05 Python
Django框架多表查询实例分析
2018/07/04 Python
pyqt5中QThread在使用时出现重复emit的实例
2019/06/21 Python
Python中的四种交换数值的方法解析
2019/11/18 Python
关于python tushare Tkinter构建的简单股票可视化查询系统(Beta v0.13)
2020/10/19 Python
python+requests实现接口测试的完整步骤
2020/10/27 Python
viagogo意大利票务平台:演唱会、体育比赛、戏剧门票
2018/01/26 全球购物
山海经纬软件测试笔试题和面试题
2013/04/02 面试题
党员服务承诺书
2014/05/28 职场文书
领导干部查摆“四风”问题自我剖析材料思想汇报
2014/10/05 职场文书
付款承诺函范文
2015/01/21 职场文书
实习指导老师意见
2015/06/04 职场文书
同学聚会感言一句话
2015/07/30 职场文书
将图片保存到mysql数据库并展示在前端页面的实现代码
2021/05/02 MySQL
HTML+CSS 实现顶部导航栏菜单制作
2021/06/03 HTML / CSS
Vue实现tab导航栏并支持左右滑动功能
2021/06/28 Vue.js
nginx配置指令之server_name的具体使用
2022/08/14 Servers