题目:

for (var i = ; i < ; i++) {
setTimeout(function() {
console.log(new Date, i);
}, );
}
console.log(new Date, i);

  1、面对这段代码时给出的结果也不尽相同,以下是典型的答案:

  A. 20% 的人会快速扫描代码,然后给出结果:0,1,2,3,4,5;
  B. 30% 的人会拿着代码逐行看,然后给出结果:5,0,1,2,3,4;
  C. 50% 的人会拿着代码仔细琢磨,然后给出结果:5,5,5,5,5,5;

  只要你对 JS 中同步和异步代码的区别、变量作用域、闭包等概念有正确的理解,就知道正确答案是 C,代码的实际输出是:

  2、如果我们约定,用箭头表示其前后的两次输出之间有 1 秒的时间间隔,而逗号表示其前后的两次输出之间的时间间隔可以忽略,代码实际运行的结果该如何描述?会有下面两种答案:

  A. 60% 的人会描述为:5 -> 5 -> 5 -> 5 -> 5,即每个 5 之间都有 1 秒的时间间隔;
  B. 40% 的人会描述为:5 -> 5,5,5,5,5,即第 1 个 5 直接输出,1 秒之后,输出 5 个 5

  这就要求候选人对 JS 中的定时器的工作机制非常熟悉,循环执行过程中,几乎同时设置了 5 个定时器,一般情况下,这些定时器都会在 1 秒之后触发,而循环完的输出是立即执行的,显而易见,正确的描述是 B。

  3、追问:闭包

  如果这道题仅仅是考察候选人对 JS 异步代码、变量作用域的理解,局限性未免太大,接下来如果期望代码的输出变成:5 -> 0,1,2,3,4,该怎么改造代码?熟悉闭包的同学很快能给出下面的解决办法:

for (var i = ; i < ; i++) {
(function(j){
setTimeout(function() {
console.log(new Date, j);
}, );
})(i);
}
console.log(new Date, i);

  巧妙的利用 IIFE(Immediately Invoked Function Expression:声明即执行的函数表达式)来解决闭包造成的问题,确实是不错的思路,但是初学者可能并不觉得这样的代码很好懂,至少笔者初入门的时候这里琢磨了一会儿才真正理解。

  有没有更符合直觉的做法?答案是有,我们只需要对循环体稍做手脚,让负责输出的那段代码能拿到每次循环的 i 值即可。该怎么做呢?利用 JS 中基本类型(Primitive Type)的参数传递是按值传递(Pass by Value)的特征,不难改造出下面的代码:

var output = function(i){
setTimeout(function() {
console.log(new Date, i);
}, );
}
for (var i = ; i < ; i++) {
output(i);//值传递传个i值过去
}
console.log(new Date, i);

  4、追问

  如果期望代码的输出变成 0 -> 1 -> 2 -> 3 -> 4 -> 5,并且要求原有的代码块中的循环和两处 console.log 不变,该怎么改造代码?新的需求可以精确的描述为:代码执行时,立即输出 0,之后每隔 1 秒依次输出 1,2,3,4,循环结束后在大概第 5 秒的时候输出 5(这里使用大概,是为了避免钻牛角尖的同学陷进去,因为 JS 中的定时器触发时机有可能是不确定的)

for (var i = ; i < ; i++) {
(function(j) {
setTimeout(function() {
console.log(new Date, j);
}, * j); // 这里修改 0~4 的定时器时间
})(i);
} setTimeout(function() { // 这里增加定时器,超时设置为 5 秒
console.log(new Date, i);
}, * i);

  不得不承认,这种做法虽粗暴有效,但是不算是能额外加分的方案。如果把这次的需求抽象为:在系列异步操作完成(每次循环都产生了 1 个异步操作)之后,再做其他的事情,代码该怎么组织?聪明的你是不是想起了什么?对,就是 Promise

  ES6、ES7的解决方案(后续)。

关于一道JS面试题的思考的更多相关文章

  1. new与属性访问的顺序,从一道JS面试题说起

    这段时间一直在研究设计模式,在看工厂模式的时候,看到一段代码 VehicleFactory.prototype.createVehicle = function ( options ) { if( o ...

  2. 一道JS面试题引发的血案

    刚入职新公司,属于公司萌新一枚,一天下午对着屏幕看代码架构时. BI项目组长给我看了一道面试别人的JS面试题. 虽然答对了,但把理由说错了,照样不及格. 话不多说,直接上题: var a = 1; s ...

  3. 一道JS面试题所引发的"血案",透过现象寻本质,再从本质看现象

    觉得本人写的不算很烂的话,可以登录关注一下我的GitHub博客,新手写东西写的不好之处,还望见谅,毕竟水平有限,写东西只为交流提高,一起学习,还望大神多加指点,指出纰漏,和提出宝贵的意见,博客会坚持写 ...

  4. 一道js面试题看变量的作用域

    [问题]分别求下面程序的输出结果: 1. <script type="text/javascript"> var a = 10; sayHi(); function s ...

  5. 一道js面试题

     当然这道面试题并不一定就能在你面试的时候遇到,但是不怕一万就怕万一,会的多一些还是好的. 问:怎么判断一串字符中哪个字符出现的最多,最多几次或者这串字符分别有哪些,每个字符出现了几次.写你请出运算代 ...

  6. 腾讯的一道js面试题(原型)

    有一只小狗叫花花,它会“汪汪”叫,他的同伴也会汪汪叫,后来环境发生了变化,新出生的狗不会再“汪汪”叫,而变成“呜呜”叫. 试通过继承来达到目的 function Dog(){ 2 this.bark ...

  7. 一道经典JS面试题

    超过80%的候选人对下面这道JS面试题的回答情况连及格都达不到.这究竟是怎样神奇的一道JS面试题?他考察了候选人的哪些能力?对正在读本文的你有什么启示? 不起眼的开始 招聘前端工程师,尤其是中高级前端 ...

  8. 一道经典的js面试题

    # 声明:学习编程语言最好的方式就是通过实例学习 ## 下面是我在博客上看到的一道js面试题,可以说非常经典,下面会以最简单的方式让你理解题目:```bashfunction Foo() { getN ...

  9. 那晚征服的一道js经典的面试题

    今天朋友共享了一道js中经典的面试题,需求是这样的 给定你任意一个字符串,让你写出一个算法,求算出该字符串中出现次数最多的一个字符,并将其结果输出 刚拿到这道题的第一感觉便是定义一个count计时器, ...

随机推荐

  1. JDK源码分析(三)——HashMap 下(基于JDK8)

    目录 概述 内部字段及构造方法 哈希值与索引计算 存储元素 扩容 删除元素 查找元素 总结 概述   在上文我们基于JDK7分析了HashMap的实现源码,介绍了HashMap的加载因子loadFac ...

  2. 1032 Sharing (25)(25 point(s))

    problem To store English words, one method is to use linked lists and store a word letter by letter. ...

  3. ubuntu18.04 安装Navicat 解决字体方框问题

    前景 最近带着看一点数据库的知识,装一下navicat,就是这个玩意儿,在我编码毫无问题的情况下,这个软件上却显示各种乱码 环境 ubuntu 18.04 navicat 12(最新版) mysql ...

  4. css平移动画的实现

    参考这位大佬的帖子:https://www.jianshu.com/p/5d8e77ef7f84

  5. Loj10153 二叉苹果树

    题目描述 有一棵二叉苹果树,如果数字有分叉,一定是分两叉,即没有只有一个儿子的节点.这棵树共 NN 个节点,标号 11 至 NN,树根编号一定为 11. 我们用一根树枝两端连接的节点编号描述一根树枝的 ...

  6. python开发_tkinter_单选按钮

    这篇blog主要是描述python中tkinter的单选按钮操作 下面是我做的demo 运行效果: ====================================== 代码部分: ===== ...

  7. VC++ 设置控件显示文本的前景色、背景色以及字体

    在每个控件开始绘制之前,都会向其父窗口发送WM_CTLCOLOR通告消息,在该消息的处理函数中,可以设置控件显示文本的前景色.背景色以及字体.该消息处理函数还要求返回一个画刷的句柄,用于在控件具体的绘 ...

  8. The YubiKey NEO -- Smartcard features

    Smartcard features on the YubiKey NEO YubiKeys are a line of small and low-cost hardware security to ...

  9. vultr vs digitalocean vs linode

    vultr官方网站:www.vultr.comdigitalocean官方网站:www.digitalocean.comlinode官方网站:www.linode.com 一般来说我们买VPS的时候都 ...

  10. ios 中是否每一个对象(尤其是在使用多线程时),都要判断一下对象是否为nil,以防止程序闪退?

    如下所示: Class messageClass = (NSClassFromString(@"MFMessageComposeViewController")); if (mes ...