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技术面试时要小心的三个问题的更多相关文章

  1. 面试时,当你有权提问时,别客气,这是个逆转的好机会(内容摘自Java Web轻量级开发面试教程)

    前些天,我在博客园里写了篇文章,如何在面试中介绍自己的项目经验,收获了2千多个点击,这无疑鼓舞了我继续分享的热情,今天我来分享另外一个面试中的甚至可以帮助大家逆转的技巧,本文来是从 java web轻 ...

  2. 十大面试问题解惑,秒杀一切HR、技术面试

    最能体现求职者能力的就是面试,能不能拿到Offer,取决于你面试时的表现,只有有准备才能在面试过程中游刃有余.小编收集了10个面试官最爱提的问题,虽然题目千变万化,但是万变不离其宗,只要掌握了答题的技 ...

  3. java技术面试之面试题大全

    转载自:http://blog.csdn.net/lijizhi19950123/article/details/77679489 Java 面试知识点总结 本篇文章会对面试中常遇到的Java技术点进 ...

  4. 面试时,问哪些问题能试出一个 Android 应用开发者真正的水平?【转自知乎】

    这几年面过的各种Android开发也有三位数了,failed的不敢说,pass的基本都没有看走眼,来得晚了也想说说我的体会. 一般面试时间短则30分钟,多则1个小时,这么点时间要全面考察一个人难度很大 ...

  5. 面试时,问哪些问题能试出一个Android应用开发者真正的水平?

    一般面试时间短则30分钟,多则1个小时,这么点时间要全面考察一个人难度很大,需要一些技巧,这里我不局限于回答题主的问题,而是分享一下我个人关于如何做好Android技术面试的一些经验: 面试前的准备 ...

  6. Amazon前技术副总裁解剖完美技术面试

    Amazon前技术副总裁解剖完美技术面试 投递人 itwriter 发布于 2014-03-03 14:30 评论(0) 有1729人阅读  原文链接  [收藏]  « » 英文原文:The Anat ...

  7. (Java后端 Java web)面试时如何展示自己非技术方面的能力(其实就是综合能力)

    这篇文章的适用范围其实不仅限于Java后端或Java Web,不过其中有些是拿这方面举例的,在其它方面,大家可以举一反三,应该也能得到些启示. 我们在面试时,会发现有些候选人技术不错,比如在Java ...

  8. 以技术面试官的经验分享毕业生和初级程序员通过面试的技巧(Java后端方向)

    本来想分享毕业生和初级程序员如何进大公司的经验,但后来一想,人各有志,有程序员或许想进成长型或创业型公司或其它类型的公司,所以就干脆来分享些提升技能和通过面试的技巧,技巧我讲,公司你选,两厢便利. 毕 ...

  9. 95%的技术面试必考的JVM知识点都在这,另附加分思路!

    概述:知识点汇总 jvm的知识点汇总共6个大方向:内存模型.类加载机制.GC垃圾回收是比较重点的内容.性能调优部分偏重实际应用,重点突出实践能力.编译器优化和执行模式部分偏重理论基础,主要掌握知识点. ...

随机推荐

  1. Linux系统iptables查看、设置、保存、备份和恢复

    不同linux系统,相关软件是否安装,会让iptables的某些命令不能执行,这里收集了大多数iptables命令,不管是Ubuntu还是Centos,都能找到相关的修改.查询.保存命令. 仅允许某些 ...

  2. 数据结构:二维ST表

    POJ2019 我们其实是很有必要把ST算法拓展到二维的,因为二维的RMQ问题还是不少的 int N,B,K; ]; int val[maxn][maxn]; ][]; ][]; 这里的N是方阵的长宽 ...

  3. 2015/8/9 到家了,学完了CodeCademy的Python

    昨天坐了20多个小时的硬座回家.发现在网络信号差的火车上也是学习的好地方.如果你的手机电量不足的话,带上两本书简直是绝配.我在火车上阅读了两百多页的内容,并没有多大的疲累,那样无聊的环境里面能看书学习 ...

  4. 使用JMeter录制脚本并调试

    仍然以禅道中添加bug为例进行录制 第一步:在JMeter中添加线程组,命名为AddBugByJMeter 第二步:在线程组下添加HTTP请求默认值 添加->配置元件->HTTP请求默认值 ...

  5. PowerDesigner逆向工程

    再用PD建表完成后导成SQL脚本然后在SQL Server中运行后生成数据库后,就想到,可不可以将直接将数据库的内容生成PD文档?经过上网查,当然可以的. 要将SQL Server中的数据库导入到PD ...

  6. 【vijos】P1659 河蟹王国

    [算法]线段树 [题解]区间加上同一个数+区间查询最大值.注意和谐值可以是负数,初始化ans为负无穷大. #include<cstdio> #include<algorithm> ...

  7. Java连接Oracle数据库的三种连接方式

    背景: 这两天在学习Oracle数据库,这里就总结下自己上课所学的知识,同时记录下来,方便整理当天所学下的知识,也同时方便日后自己查询. SQL语句的话,这里我就不多讲了,感觉和其他的数据库(MySQ ...

  8. Vue前端开发规范(山东数漫江湖)

    一.强制 1. 组件名为多个单词 组件名应该始终是多个单词的,根组件 App 除外. 正例: export default { name: 'TodoItem', // ... } 反例: expor ...

  9. 理解js中私有变量

    私有变量在js中是个什么概念.当下我的认识是var所定义的变量,实际可以理解为属性和方法,或者单单是临时存储器,不归属任何对象. 一个声明函数: function a(){  var v = &quo ...

  10. Python第三方库SnowNLP(Simplified Chinese Text Processing)快速入门与进阶

    简介 github地址:https://github.com/isnowfy/snownlp SnowNLP是一个python写的类库,可以方便的处理中文文本内容,是受到了TextBlob的启发而写的 ...