• 记一次面试


    关于一道经常碰到的面试题

    最近面试经常碰到这样一道题(或者类似):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();
    
    
  • 相关阅读:
    关于网络字节序(network byte order)和主机字节序(host byte order)
    关于垃圾回收,我来解释下为什么LocalConnection可以实现垃圾回收
    解决Form中ExternalInterface的Bug问题
    AS3里var aa:String是null还是""?
    IE并发连接限制(as)
    tar
    mysql默认端口号3306
    flex经验
    这个游戏不错
    nginx介绍
  • 原文地址:https://www.cnblogs.com/cyrus-br/p/10519523.html
Copyright © 2020-2023  润新知