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 Array数组对象的扩展函数代码
May 22 Javascript
js下拉菜单语言选项简单实现
Sep 23 Javascript
jQuery控制的不同方向的滑动(向左、向右滑动等)
Jul 18 Javascript
javascript中解析四则运算表达式的算法和示例
Aug 11 Javascript
引用其它js时如何同时处理多个window.onload事件
Sep 02 Javascript
JQuery工具函数汇总
Jun 15 Javascript
jQuery实现气球弹出框式的侧边导航菜单效果
Sep 22 Javascript
微信小程序上滑加载下拉刷新(onscrollLower)分批加载数据(二)
May 11 Javascript
详解从Vue.js源码看异步更新DOM策略及nextTick
Oct 11 Javascript
微信小程序首页的分类功能和搜索功能的实现思路及代码详解
Sep 11 Javascript
微信浏览器下拉黑边解决方案 wScroollFix
Jan 21 Javascript
详解JavaScript 高阶函数
Sep 14 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
改德生G88 - 加装等响度低音提升电路
2021/03/02 无线电
PHP入门速成(2)
2006/10/09 PHP
wampserver改变默认网站目录的办法
2015/08/05 PHP
判断脚本加载是否完成的方法
2009/05/26 Javascript
javascript基础第一章 JavaScript与用户端
2010/07/22 Javascript
探讨JavaScript中声明全局变量三种方式的异同
2013/12/03 Javascript
javascript使用avalon绑定实现checkbox全选
2015/05/06 Javascript
JS实现的表格行上下移动操作示例
2016/08/03 Javascript
基于JS分页控件实现简单美观仿淘宝分页按钮效果
2016/11/07 Javascript
纯javaScript、jQuery实现个性化图片轮播【推荐】
2017/01/08 Javascript
详解在vue-cli中引用jQuery、bootstrap以及使用sass、less编写css
2017/11/08 jQuery
js实现rem自动匹配计算font-size的示例
2017/11/18 Javascript
微信小程序实现banner图轮播效果
2020/06/28 Javascript
ES6 新增的创建数组的方法(小结)
2019/08/01 Javascript
electron-vue开发环境内存泄漏问题汇总
2019/10/10 Javascript
[07:09]DOTA2-DPC中国联赛 正赛 Ehome vs Elephant 选手采访
2021/03/11 DOTA
python负载均衡的简单实现方法
2018/02/04 Python
python爬虫获取小区经纬度以及结构化地址
2018/12/30 Python
pandas读取CSV文件时查看修改各列的数据类型格式
2019/07/07 Python
python3中的eval和exec的区别与联系
2019/10/10 Python
Pytorch自己加载单通道图片用作数据集训练的实例
2020/01/18 Python
CSS3伪类选择器:nth-child()
2009/04/02 HTML / CSS
巧用CSS3的calc()宽度计算做响应模式布局的方法
2018/03/22 HTML / CSS
Aeropostale官网:美国著名校园品牌及青少年服饰品牌
2019/03/21 全球购物
某/etc/fstab文件中的某行如下: /dev/had5 /mnt/dosdata msdos defaults,usrquota 1 2 请解释其含义
2013/09/18 面试题
东方红海科技面试题软件测试方面
2012/02/08 面试题
暑期实习鉴定
2013/12/16 职场文书
超市营业员岗位职责
2013/12/20 职场文书
医院实习介绍信
2014/01/12 职场文书
致全体运动员广播稿
2014/02/01 职场文书
机关作风整顿个人整改措施2014
2014/09/17 职场文书
出租车拒载检讨书
2015/01/28 职场文书
悬空寺导游词
2015/02/05 职场文书
Java面试题冲刺第十八天--Spring框架3
2021/08/07 面试题
MySQL分区表管理命令汇总
2022/03/21 MySQL
vue使用element-ui按需引入
2022/05/20 Vue.js