最近一直在写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);

 

理论上,通过对象复制也是可行的。


评论(0条)

请登录后评论
moban

moban Rank: 16

0

0

0

( 此人很懒并没有留下什么~~ )