• JavaScript中的this


    本文尽量避免概念性的讲解,那样太抽象

    所以下面以一些简单的例子,从易到难对this的用法总结



     
    1.方法中的this会指向当前执行该方法的对象 如:

    var name = "window"
    
    var Tom = {
      name:"Tom";
      show:function(){
       console.log(this+":"+this.name)
      } 
    
    } Tom.show(); //Tom



    2.方法中的this不会指向声明它的对象 如下

    var Bob={
      name:"Bob",
      show:function(){
      console.log(this+":"+this.name)
      } 
    }; 
    
    var Tom={ 
      name:"Tom", 
      show:Bob.show 
    }; 
    
    Tom.show() ; //Tom

    尽管console.log是Bob对象环境中声明的 ,但方法是由Tom对象调用执行

    所以this总是会指向当前执行的对象,而不是声明的对象

    其本质原因是:Bob.show方法赋值给Tom.show方法的时候不会把Bob对象也给绑定过去

    下面是个将对象绑定过去的例子

     


     3.嵌套对象中,this指向直接绑定它的对象

    var Bob={
      name:"Bob",
      Tom:{
        name:"Tom",
        show:function(){console.log(this+":"+this.name)}
      }
    }
    
    Bob.Tom.show();  //Tom



     

    4.用变量保存方法的执行结果,其执行对象仍然是Tom

    var name="window";
    var Tom={
      name:"Tom",
      show:function(){
      console.log(this+":"+this.name)
      }
    };
    
    var fun=Tom.show();
    fun();              //Tom

    此处fun所赋值的是Tom.show函数执行的结果,也就是Tom

    上面的例子其实是下面所做对照的

     

     

    5.用变量保存方法的内容,其执行对象是window

    var name="window";
    var Tom={
      name:"Tom",
      show:function(){
          console.log(this+":"+this.name)
      }
    };
    
    fun=Tom.show;
    fun();              //Window

    因为fun赋值的只是方法的内容,并没有绑定在Tom对象上,所以fun执行对象是window对象

     


     

     6.若指明了调用方法的对象的话,this会指向调用其的对象 如下:

    var name = "window";
    var Bob= {
        name:"Bob",
        show:function(){console.log(this.name);}
        };
    
     var Tom= {name: "Tom"};
     Bob.show();                   //Bob
     Bob.show.apply();             //window
     Bob.show.apply(Tom);          //Tom

     

     

     

     当然call()也差不多类似,apply和call用于指明由哪个对象去执行该方法

     

     


    7.函数作为构造器时,this会指向新建的对象,如下

    function Tom(name,age){
      this.name=name;  
      this.age=age;
      this.getInfo=function(){
          console.log(this.name+" is "+this.age)
       }
    }
    
    var Bob = new Tom("Bob",45);
    
    Bob.getInfo();  //Bob is 45
    
     
     

     

     

     

    我们来点进阶的东西!!!

    下面例子要解释的通 则需要两个重要的概念

    延迟执行!

    延迟调用!



    8.将对象赋值给变量后,再调用方法,执行的对象仍然是Tom

    var name="window";
    var Tom={
      name:"Tom",
      show:function(){console.log(this.name)},
      wait:function(){
                 var that=this;
                 that.show();
             }
      };
    
    Tom.wait();  //Tom

    因为show绑定在that的对象里,而that的值是对象Tom,所以执行的对象指向了Tom

    "将对象保存到变量,再去调用方法",这个过程称为延迟调用,若不明白没关系

    接着往下看

      


    9.在函数上下文中若没有指明执行方法的对象,那么会由全局对象window来执行

    var name="window";
    var Tom={
      name:"Tom",
      show:function(){console.log(this.name)},
      wait:function(){
                 var fun=this.show;
                 fun();
             }
      };
    
    Tom.wait();  //window

    fun赋值的是方法的内容,没有绑定于Tom对象里,因此执行的对象是window

    上面的"把方法赋值给变量,再调用"这个过程可以看做延迟执行

    延迟执行方法会导致该方法失去对象的绑定,导致对象由window执行执行

    下面是一些延迟调用的例子

     

    10.匿名函数的延迟

    var name="window";
    var Tom={
      name:"Tom",
      show:function(){console.log(this.name)},
      wait:function(){!function(call){call();}(this.show)}
      }
    
    Tom.wait();    //Window

     

     

     



    11.setTimeout、setInterval函数延迟
    这里只以setTimeout为例子

    var name="window";
    var Tom={
      name:"Tom",
      show:function(){console.log(this.name)},
      wait:function(){setTimeout(this.show,1000)}
      }
     
    Tom.wait();    //window

     

     

    从上面两个例子可以得出:延迟执行会使得执行方法的对象更改为全局对象window

    那么如何防止这种更改呢,我们尝试下面一招

     


    12. 在延迟的环境下 尝试让Tom加班(对象也跟着延迟)

    var name="window";
    var Tom={  
      name:"Tom",
      show:function(){console.log(this.name)},
      wait:function(){setTimeout(Tom.show,1000)} 
    }
    
    Tom.wait();    //window 

     

     

    上面中this就直接指明Tom,尝试让Tom加班,但是结果仍然为Window对象

    因为Tom.show放在第一个参数里,就相当于这个方法被保存到一个变量里

    然后经过延迟后再执行这个变量,而保存的时候依然没有绑定到对象Tom,因此执行的对象依然是window

    这个和上面第9个例子是一个道理的。称为延迟执行,只不过这次的延迟执行是用了setTimeout来实现

     

    那么难道没有办法避免延迟执行方法导致执行对象被更改了吗?非也!

    让对象也跟着延迟就可以做到!如下

     

     

     13.虽然延迟会导致方法的执行对象被更改为Window 但也有办法防止执行对象更改 如下

    var name="window"
    var  Tom ={  
        name : "Tom",  
        show : function(){console.log(this.name);},  
        wait:  function(){
        var that=this;
        setTimeout(function(){that.show()},1000)}  
              }
    
    Tom.wait();    //Tom 

     

    通过变量保存对象,再使用变量去调用方法,达到执行的对象也跟着延迟的效果


     


    14.eval函数的延迟

    对于eval比较特殊

    在eval环境下,执行的对象就是当前作用域的对象 如下

    var name="window";
    var Bob={
      name:"Bob",
      showName: function(){ eval("console.log(this.name)"); }
      };
    
    Bob.showName(); //Bob
    
     

     

     


    15.eval函数的环境下,不会受到延迟而影响函数执行的对象

    之所以eval特殊是因为eval不受延迟的影响

    var name="window";
    var that;
    var Tom={
      name:"Tom",
      show:function(){console.log(this.name)},
      wait:function(){that=this;setTimeout("that.show()",1000)}
      }
     
    Tom.wait();    //Tom
    
     

     

    也许你会觉得上面的代码没有eval函数的身影

    其实setTimeout函数的第一个参数就是eval环境

    他会指向当前执行作用域的执行对象,忽略延迟方法延迟调用

     

     

    点击下面可以看看田小计划对JavaScript的this是如何见解

    http://www.cnblogs.com/wilber2013/p/4909505.html

    能把上面例子都理解了,那么this是一把有利的刀!

    当然如果不能理解,那么像闭包一样 尽量的少用!

  • 相关阅读:
    ORM的概念, ORM到底是什么
    EM算法
    贝叶斯方法的m-估计
    概率图模型之:贝叶斯网络
    决策树学习
    各种聚类算法的比较
    聚类算法:K均值
    Entity Framework + WCF 远程调用出错
    使用Entity Framework时,序列化出错
    WCF基础知识
  • 原文地址:https://www.cnblogs.com/demonxian3/p/6254209.html
Copyright © 2020-2023  润新知