avaScript技术面试时要小心的三个问题
JavaScript是所有现代浏览器的官方语言。同样的,JavaScript面试题出现在各种各样的面试中。
这篇文章不是讲述JavaScript最新的库、日常的开发实践,或是ES6的新功能。当然了,上面说的这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个元素,没问题,但是如果有10000个待办事项呢(程序可能还有其他事情要做)?接下来你会创建10000个事件监听函数绑定要每个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: 在循环内使用闭包
闭包问题常常在面试中被提出,面试官能通过它估算出你对JavaScript的熟悉程度,同时了解你对闭包是否熟悉。
闭包的精髓就是:在外部函数中可以读取到内部函数的作用域。闭包可以做这些事:创建私有变量、创建私有函数等。大多数关于闭包的面试题像这样:
循环一个数组,并在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的值,在循环结束后i等于4,因为它的循环周期经历了0,1,2,3,4,最终在i为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秒内被触发几千次。这可能会导致很严重的性能问题。
如果你们在面试中讨论构建一个应用,谈到类似滚动、改变窗口尺寸或键盘按下的事件时,一定会提及函数防抖、函数节流(Throttling)去优化页面速度和性能。一个真实的案例,来自guest post on css-tricks:
在2011年,一个问题在Twitter上被提出:当你滚动Twitter feed时,它会十分缓慢且迟钝。John Resig就这个问题发布了一篇博客,它解释了直接绑定函数到滚动事件上是多么糟糕和昂贵的事。
函数防抖是解决这个问题的一种方式,通过限制函数被调用的次数。一个正确实现函数防抖的方法是:把多个函数放在一个函数里调用,隔一定时间执行一次。这里有一个使用原生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毫秒内全部调用。
想了解更多关于函数防抖和函数节流的信息,下面的文章和教程可能会帮到你:
译者注:之前听朋友讲过这个例子,我就很清晰的分辨了两者的区别:
想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应。假设电梯有两种运行策略 throttle 和 debounce ,超时设定为15秒,不考虑容量限制。
throttle 策略的电梯。保证如果电梯第一个人进来后,15秒后准时运送一次,不等待。如果没有人,则待机。
debounce 策略的电梯。如果电梯里有人进来,等待15秒。如果又人进来,15秒等待重新计时,直到15秒超时,开始运送。
本文由Rockjins Blog翻译,转载请与译者联系。否则将追究法律责任。
avaScript技术面试时要小心的三个问题的更多相关文章
- 面试时,当你有权提问时,别客气,这是个逆转的好机会(内容摘自Java Web轻量级开发面试教程)
前些天,我在博客园里写了篇文章,如何在面试中介绍自己的项目经验,收获了2千多个点击,这无疑鼓舞了我继续分享的热情,今天我来分享另外一个面试中的甚至可以帮助大家逆转的技巧,本文来是从 java web轻 ...
- 十大面试问题解惑,秒杀一切HR、技术面试
最能体现求职者能力的就是面试,能不能拿到Offer,取决于你面试时的表现,只有有准备才能在面试过程中游刃有余.小编收集了10个面试官最爱提的问题,虽然题目千变万化,但是万变不离其宗,只要掌握了答题的技 ...
- java技术面试之面试题大全
转载自:http://blog.csdn.net/lijizhi19950123/article/details/77679489 Java 面试知识点总结 本篇文章会对面试中常遇到的Java技术点进 ...
- 面试时,问哪些问题能试出一个 Android 应用开发者真正的水平?【转自知乎】
这几年面过的各种Android开发也有三位数了,failed的不敢说,pass的基本都没有看走眼,来得晚了也想说说我的体会. 一般面试时间短则30分钟,多则1个小时,这么点时间要全面考察一个人难度很大 ...
- 面试时,问哪些问题能试出一个Android应用开发者真正的水平?
一般面试时间短则30分钟,多则1个小时,这么点时间要全面考察一个人难度很大,需要一些技巧,这里我不局限于回答题主的问题,而是分享一下我个人关于如何做好Android技术面试的一些经验: 面试前的准备 ...
- Amazon前技术副总裁解剖完美技术面试
Amazon前技术副总裁解剖完美技术面试 投递人 itwriter 发布于 2014-03-03 14:30 评论(0) 有1729人阅读 原文链接 [收藏] « » 英文原文:The Anat ...
- (Java后端 Java web)面试时如何展示自己非技术方面的能力(其实就是综合能力)
这篇文章的适用范围其实不仅限于Java后端或Java Web,不过其中有些是拿这方面举例的,在其它方面,大家可以举一反三,应该也能得到些启示. 我们在面试时,会发现有些候选人技术不错,比如在Java ...
- 以技术面试官的经验分享毕业生和初级程序员通过面试的技巧(Java后端方向)
本来想分享毕业生和初级程序员如何进大公司的经验,但后来一想,人各有志,有程序员或许想进成长型或创业型公司或其它类型的公司,所以就干脆来分享些提升技能和通过面试的技巧,技巧我讲,公司你选,两厢便利. 毕 ...
- 95%的技术面试必考的JVM知识点都在这,另附加分思路!
概述:知识点汇总 jvm的知识点汇总共6个大方向:内存模型.类加载机制.GC垃圾回收是比较重点的内容.性能调优部分偏重实际应用,重点突出实践能力.编译器优化和执行模式部分偏重理论基础,主要掌握知识点. ...
随机推荐
- SpringMVC 用注解Annotation驱动的IoC功能@Autowired @Component
转载自:http://blog.csdn.net/lufeng20/article/details/7598564 本文分为三个部分:概述.使用注解进行属性注入.使用注解进行Bean的自动定义. 一, ...
- Beagleboneblack的MLO文件干了些啥
Beagleboneblack在启动linux之前还有三个启动阶段: ROM code --> MLO --> u-boot --> kernel 先看看ROM code干了 ...
- 用一个时钟在FPGA中计算直方图
直方图对数字数据的分析通常是一种有用的工具.不过,要从一个直方图获得可靠的结果,必须获得大量数据,通常是要10万到100万个点.如果需要分析一个ADC的数字输出,可以采用一片FPGA(图1). 图中显 ...
- 【BZOJ2850】巧克力王国 [KD-tree]
巧克力王国 Time Limit: 60 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 巧克力王国里的巧克力都是由牛奶和 ...
- Morley's Theorem (计算几何基础+向量点积、叉积、旋转、夹角等+两直线的交点)
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
- Little Mathematics Knowledge 数学小常识
The sum of arithmetic sequence The sum of geometric sequence A special formula : n·n! = (n+1)! - n! ...
- mave的依赖范围
compile(编译范围) compile是默认的范围:如果没有提供一个范围,那该依赖的范围就是编译范 围.编译范围依赖在所有的classpath中可用,同时它们也会被打包. provided(已提供 ...
- 2.0 docker安装
问题列表: Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again 解:处 ...
- Coursera助学金申请模板
讲真,我觉得coursera的课还挺贵的.但是它有助学金系统,非常对我们穷学生友好了,而且基本上申请的都会批.不过现在助学金需要15个工作日才有答复,所以注意要提前申请. 有两大段要填. 虽然写的挺烂 ...
- Opencv模块功能介绍
本文为原创作品,转载请注明出处 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和http://www.cnblogs.com/xujianqing/ 站在巨 ...