记一次面试

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值打印, 所以结果一样。

问题原因

这里产生问题的原因在于:

  1. for语句不会像其他语言具有块级作用域(也是js变量声明提升)。
  2. 所有的访问循环变量的值,都是延时访问了。
  3. 访问的i都指向同一个i。

解决方法

其实,核心问题,就是等待循环结束,才去访问i,而且访问的是同一个i。
解决思路:两种 改变访问时机, 改变访问变量。

在改变之前访问i。

for( var i = 0; i < 5; i++){
    console.log(i);
}

这样做好像没什么意义。

为每一语句保存一个i值

  1. 让for语句具有块级作用域
    这是es6的语法规则: 使用let. (这是最简单的一种形式)
function fun(){
    for (let i = 0; i < 5; i++){
        setTimeout(()=>{
            console.log(i)
        },0); 
    }
}
fun();

用let代替var来声明变量,就可以把变量的作用域限制在当前代码块中也就是{}

  1. 使用闭包
    函数是具有自己的作用域的。在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。


分割线(这对之前问题的处理)

  1. 使用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();

以上是关于记一次面试的主要内容,如果未能解决你的问题,请参考以下文章

记一次面试一直出现的题——数组去重

年前最后一波装逼记一次阿里面试,我是如何用一行代码解决约瑟夫环问题的

记一次HashMap面试

记一次面试

初面蚂蚁金服,记一次美团Java研发岗的面试经历

记一次阿里云的面试