记一次面试
Posted cyrus-br
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次面试相关的知识,希望对你有一定的参考价值。
关于一道经常碰到的面试题
最近面试经常碰到这样一道题(或者类似):ps.因为我阿姨不会就详细分析吧。
var btns = document.getElementsByClassName('btn');
for(let i = 0; i < btns.length; i++){
btn[i].onclick = function(){
console.log(i)
}
}
这个之前说过,因为面试的时候,说了主要看闭包。所以也没有多想。
function fun(){
for (var i = 0; i < 5; i++){
setTimeout(()=>{
console.log(i)
},0);
}
}
fun();
问题
其实,通过分析就不难看出,核心点问题都是, 在一个循环内,延时打印循环变量。 所有的结果一样。
问题分析
因为js的变量有提升作用,所以可以将程序改成成更加直观的形式。
var i = 0;
function fun(){
while (i < 5){
setTimeout(()=>{
console.log(i) // 这里访问的i 都是 之前定义的 i
},1000);
i++; // 这里访问的i 也是 之前定义的 i
}
}
fun();
我们改成程序之后,就可以看到了。 打印语句的i,因为都是在等待i变换之后,取i值打印, 所以结果一样。
问题原因
这里产生问题的原因在于:
- for语句不会像其他语言具有块级作用域(也是js变量声明提升)。
- 所有的访问循环变量的值,都是延时访问了。
- 访问的i都指向同一个i。
解决方法
其实,核心问题,就是等待循环结束,才去访问i,而且访问的是同一个i。
解决思路:两种 改变访问时机, 改变访问变量。
在改变之前访问i。
for( var i = 0; i < 5; i++){
console.log(i);
}
这样做好像没什么意义。
为每一语句保存一个i值
- 让for语句具有块级作用域
这是es6的语法规则: 使用let. (这是最简单的一种形式)
function fun(){
for (let i = 0; i < 5; i++){
setTimeout(()=>{
console.log(i)
},0);
}
}
fun();
用let代替var来声明变量,就可以把变量的作用域限制在当前代码块中也就是{}
- 使用闭包
函数是具有自己的作用域的。在es6之前,都是使用闭包来实现块作用域
function fun(){
for (var i = 0; i < 5; i++){
setTimeout((function(i_){
return function(){
console.log(i_)
}
})(i),0);
}
}
fun();
其实, 也就是用 立即执行函数参数i_ 来保存 i 值 。 当然你也可以把i_写成i。
分割线(这对之前问题的处理)
- 使用setTime调用时候可以传递参数的特性。
难道之前面试问我的是这么做?
function fun(){
for (var i = 0; i < 5; i++){
var promise = new Promise(function(resolve, reject){
setTimeout(resolve,1000,i);
}); // 这个是立即执行
promise.then(function(value){ // 回调执行
console.log(value);
})
}
}
fun();
下面代码也可以实现,其实,你就会发现, 这是因为 setTimeout 函数 可以调用给函数传递参数的原因, 。
function fun(){
for (var i = 0; i < 5; i++){
setTimeout((i)=>{
console.log(i)
},0,i);
}
}
fun();
以上是关于记一次面试的主要内容,如果未能解决你的问题,请参考以下文章