首先,这些题目不知道在网上有没有,反正我是被坑过了,欲哭无泪的那种.javascript
题目是这样的:
使用console.log方法打印变量,若是出现延迟1秒后输出用=>表示,若是是连续输出用,表示。java
例如:1=>2,3,4=>5,表示输出1后,延迟1秒后连续输出二、三、4,再延迟1秒输出5es6
for(var i=0;i<5;i++) { setTimeout(function(){ console.log(i) }, 1000) } console.log(i)
怎么样,够简单吧,可是我特么居然答错了,真心想抽本身几下。
我给出的回答是:5=>4=>4=>4=>4=>4
下面,我说明如下我当时的脑壳里面是怎么想的:面试
for(var i=0;i<5;i++) { setTimeout(function(){ console.log(i) // 在这个地方,我认为在for中限制的条件是i<5,那么这里就会是4 }, 1000) // 不知道为何我当时会认为这里延迟的1秒会默认*i,致使=>4=>4=>4=>4=>4 } // 第一个5, 由于var关键字能够提高变量的做用域,出了for循环体做用域外, 其实仍是可以被访问到的,然而在for循环中最后一次对i的操做是i++,因此这里会输出5。 console.log(i)
面试官仍是很不错的,他反复提醒我再检查检查,有没有什么遗漏。因而我盯着for里面看了大概有30秒,愣是没发现问题。而后面试官很是和善可亲的微笑着跟我对了一遍for,当对到i=5的时候,个人脑壳当时就直冒冷汗,我擦!正确的答案应该是:5=>5,5,5,5,5闭包
再从新分析如下,上面的代码执行过程至关于:async
// for循环了5次,调用setTimeout方法也是5次,可是setTimeout的延迟都是1秒, // 等setTimeout中的callback函数执行的时候,i的值已是5了, // 因此最终1秒后会连续打印出5个5 setTimeout(function(){ console.log(i) // 第2个5 }, 1000) setTimeout(function(){ console.log(i) // 第3个5 }, 1000) setTimeout(function(){ console.log(i) // 第4个5 }, 1000) setTimeout(function(){ console.log(i) // 第5个5 }, 1000) setTimeout(function(){ console.log(i) // 第6个5 }, 1000) // 这里没啥好说的 console.log(i)
这个其实是考察你对闭包的掌握状况,我给出的回答是:函数
答案1:code
for(var i=0;i<5;i++) { setTimeout(function(j){ console.log(j) }, 1000, i) // 经过setTimeout的第三个参数把i传入给callback函数的参数j } console.log(i) // 这里不用动
答案2:ip
for(var i=0;i<5;i++) { (function(j){ // j就是外部传入的参数i setTimeout(function(){ console.log(j) }, 1000) })(i) // 包一层当即执行函数(IIFE),把i传入 } console.log(i) // 这里不用动
作这道题的时候,有一个插曲,我最开始想的是把for中的var换成let就行了,面试官说:一看就知道大家用es6用的太多,我听了以后,仍是立刻反应过来了,确实不能换成let。作用域
错误的答案:
// for中的变量i用let关键字声明以后,只在for循环体内的做用域可以访问到, // 出了这个循环体做用域,外部就访问不到了。 for(let i=0;i<5;i++) { setTimeout(function(){ console.log(i) }, 1000) } // 因此,这里的i会是undefined console.log(i)
看了这个题我想了大概有2分钟,面试官说,随便你怎么改,你只要能输出这个结果就行,无奈我用了一个最最最最low的办法。
const count = 5 for(let i=0;i<count;i++) { setTimeout(function(j){ console.log(j) }, 1000 * i, i) } setTimeout(function(){ console.log(i) }, 1000 * i)
面试官看了看说,好吧这个也算你答对了,可是你能够尝试如下es六、es7的特性去完成这个(疯狂暗示),因而我分析了一下:
// 要保证从上往下的执行顺序 for(var i=0;i<5;i++) { // 这里的setTimeout会分别输出0=>1=>2=>3=>4 setTimeout(function(){ console.log(i) }, 1000) } **// 问题就是在这里,如何保证for里面的setTimeout所有执行完成以后,再执行下面的输出?** // 这里的i输出的应该是最后一个=>5 console.log(i)
我想了大概有2分钟,决定用generator函数,可是还没写到一半的时候,面试官叫停了:其实能够用es7中的async、await配合Promise.all()来完成,不必用generator,你怎么还退到上一个版本了呢。
好吧,我感受此次面试应该是GG了。
最后我仍是贴出我用generator实现的代码
function * G() { for(var i=0;i<5;i++){ yield i } return i } var gg = G() do { const {value, done} = gg.next() setTimeout(() => { console.log(value) }, 1000 * value); if (done) { break; } } while(true)
面试官想要的答案:
(async function () { var i = 0 function a() { var array = [] for(;i<5;i++){ array[i] = new Promise((resolve) => { setTimeout((j) => { console.log(j) resolve() }, 1000 * i, i); }) } return array } await Promise.all(a()) console.log(i) })()
最最后,我想说这真的是一次印象很是深入的面试,上面的这些题的知识点平时在开发的过程当中,实际上是比较常见的,只不过比较分散,可是集中到一块儿可能就会蒙蔽你的眼睛,影响你的判断。 本身继续加油吧!