zoukankan      html  css  js  c++  java
  • js中this和回调方法循环-我们到底能走多远系列(35)

    我们到底能走多远系列(35)

    扯淡:

      13年最后一个月了,你们在13年初的计划实现了吗?还来得及吗?

      请加油~

    主题:

    最近一直在写js,遇到了几个问题,可能初入门的时候都会遇到吧,总结下。

    例子:
    var x =9;
    var fobj ={
        x:1,
        test:function(callback){
            var x= 2;
            callback();
        }
    }
    function pp(){
        var x = 3;
        fobj.test(function(){
            alert(this.x)//9
        })
    }
    pp();
    上面这段代码打印出的是 9 ,可以看到test的调用者是fobj,可是在test中执行回调时callback();这调代码前面是空的。所以其实是有一个作为的全局调用了这个回调,所以,执行回调代码时的this则就是全局环境。
     
         总结一下:当方法被一个对象调用的时候:fobj.test(),那么this是绑定在fobj上的。
                        如果不是这样调用:callback() 那么this则绑定在全局变量上。
     
         回调函数中的this,最好不要使用,因为this指的是,调用函数的那个对象。
    回调函数作为参数传入一个方法,我们就不能确定这个方法中的环境变量是怎样了的。
     
    Function的bind方法:
    var x =9;
    var fobj ={
        x:1,
        test:function(callback){
            var x= 2;
            callback();
        }
    }
    function pp(){
        var x = 3;
        fobj.test(function(){
            alert(this.x)//1
        }.bind(fobj))
    }
    pp();
    使用bind方法后输出为1,其中的this指向了fobj。
     
    Array的forEach方法
    在使用forEach方法的时候,也有类似的场景,这个方法提供了参数传入指定的上下文
    例子:
    var x = "test";
    var ojb = {
        x : "obj"
    }
    function pp(){
        var t = [1,2,3,4];
        t.forEach(function(value,index){
           alert(this.x + value);
        },ojb);
    }
    pp();
    以上代码就指定了forEach中第一个参数匿名函数的上下文为ojb。
    详细的参数规则和方法使用教程:摸我
     
    循环回调函数问题:
    例子:
    for(var i=1;i<4;i++){
       doCallBack(function(){
           alert(i);//1,2,3
       });
    }
    
    function doCallBack(callback){
        var x = "callback";
        callback();
    }    
      
         上面的代码执行结果看似没有问题,在实际项目中,使用回调异步一些耗时工作,比如数据库的查询,写node的时候这种情况很多,那么会出现什么样的结果呢?
    看下下面的模拟:
    for(var i=1;i<4;i++){
       doCallBack(function(){
           setTimeout(function(){alert(i);},1000)//4,4,4
       });
    }
    
    function doCallBack(callback){
        var x = "callback";
        callback();
    }
         全部打印4,导致这个发生的原因是因为回调函数中的耗时工作是异步的,也就是说第一次循环执行到doCallBack的时候,直接跳到for的末尾,然后开始第二次循环,一次类推,当循环达到i的最大值4的时候跳出循环,而延迟的工作开始了,这时候他们打印i,而这个i被加到了4,所以就有了全部打印4的结果。
     
    先理解下js中的作用域链,比如下面的代码型式:
    function A(){
         var i =1;
         function B(){
              i =2;
              ...
         }
    }
    function C(){...}
         B方法的作用域链就像这样 B内部 ->A内部 ->全局,也就是说方法内部的方法是可以引用到外部方法的变量的,如果这个B方法在C被调用,那么我们就实现C方法使用到了同级方法的作用域。其实我们就会认为这是一个闭包的行为。这样的作用域链机制,带来的副作用在前面提到的例子中展示了。
     
    解决办法: 
    for(var i=1;i<4;i++){
       (function(x){
          doCallBack(function(){
            // alert(x)
             setTimeout(function(){alert(x);},1000);//1,2,3
          });
       })(i) 
    }
    
    function doCallBack(callback){
        callback();
    }
         这里我们可以看到加了个匿名方法包在外面然后直接传入i,执行方法。还利用了这个i作为基本类型是按值传递的,所以在函数内部是一个复制的值,外部i的自增将不能改变内部函数的x的值了。
     
    也可以写成这样:
    for(var i=1;i<4;i++){
       !function(x){
          doCallBack(function(){
            // alert(x)
             setTimeout(function(){alert(x);},1000);//1,2,3
          });
       }(i)
    }
    
    function doCallBack(callback){
        callback();
    }
    用递归的办法:感受下
    function doCallBack(x){
        if(x<=1){
           return 1;
        }else{
           setTimeout(function(){alert(x);},1000);//4,3,2
           return doCallBack(x-1);
        }
       
    }
    doCallBack(4)
    实际应用中,遇到引用类型的时候,展示使用里很土的办法先解决一下
    代码类似:(3次循环,修改成下面代码)
    var rstScoreMsg0 = {
                score : scores[0],
                username : uids[0],
                expLoser : expLoser,
                expWinner : expWinner,
                uid : 0
            };
            var rstScoreMsg1 = {
                score : scores[1],
                username : uids[1],
                expLoser : expLoser,
                expWinner : expWinner,
                uid : 0
            };
            var rstScoreMsg2 = {
                score : scores[2],
                username : uids[2],
                expLoser : expLoser,
                expWinner : expWinner,
                uid : 0
            };
    
            recordUser(rstScoreMsg0);
            recordUser(rstScoreMsg1);
            recordUser(rstScoreMsg2);
     
    理论上,通过对象复制也是可行的。
     
     
     
     
     

    让我们继续前行

    ----------------------------------------------------------------------

    努力不一定成功,但不努力肯定不会成功。
  • 相关阅读:
    集合:HashMap原理
    监控管理
    jvm(内存分配和回收策略、字节码执行引擎、运行时栈的结构)
    jvm:收集器
    多线程(线程的四种创建方式)
    scrapy之下载器中间件(Download Middleware)
    scrapy之Spider
    Scrapy之原理&提取数据
    小程序之请求服务器资源注意问题
    小程序之页面跳转
  • 原文地址:https://www.cnblogs.com/killbug/p/3457445.html
Copyright © 2011-2022 走看看