zoukankan      html  css  js  c++  java
  • 深入理解javascript之this

    javascript中的this含义很丰富,它能够是全局对象,当前对象或者是随意对象,这都取决于函数的调用方式。函数有下面几种调用方式:作为对象方法调用、作为函数调用、作为构造函数调用、apply或call调用。

    对象方法调用

    作为对象方法调用的时候。this会被绑定到该对象。

    var point = { 
     x : 0, 
     y : 0, 
     moveTo : function(x, y) { 
         this.x = this.x + x; 
         this.y = this.y + y; 
         } 
     }; 
    
     point.moveTo(1, 1)//this 绑定到当前对象,即 point 对象
    
    
    

    这里我想强调一点内容,就是this是在函数运行的时候去获取相应的值,而不是函数定义时。即使是对象方法调用,假设该方法的函数属性以函数名的形式传入别的作用域,也会改变this的指向。我举一个样例:

    var a = {
    	aa : 0,
    	bb : 0,
    	fun : function(x,y){
    		this.aa = this.aa + x;
    		this.bb = this.bb + y;
    	}
    };
    var aa = 1;
    var b = {
    	aa:0,
    	bb:0,
    	fun : function(){return this.aa;}
    }	
    a.fun(3,2);
    document.write(a.aa);//3,this指向对象本身
    document.write(b.fun());//0,this指向对象本身
    (function(aa){//注意传入的是函数。而不是函数运行的结果
    	var c = aa();
    	document.write(c);//1 , 因为fun在该处运行,导致this不再指向对象本身。而是这里的window
    })(b.fun);	


    这样就明确了吧。这是一个easy混淆的地方。


    函数调用

    函数也能够直接被调用,这个时候this被绑定到了全局对象。

     var x = 1;
      function test(){
        this.x = 0;
      }
      test();
      alert(x); //0
    

    但这样就会出现一些问题。就是在函数内部定义的函数。其this也会指向全局。而和我们希望的恰恰相反。代码例如以下:

    var point = { 
     x : 0, 
     y : 0, 
     moveTo : function(x, y) { 
         // 内部函数
         var moveX = function(x) { 
         this.x = x;//this 绑定到了全局
        }; 
        // 内部函数
        var moveY = function(y) { 
        this.y = y;//this 绑定到了全局
        }; 
    
        moveX(x); 
        moveY(y); 
        } 
     }; 
     point.moveTo(1, 1); 
     point.x; //==>0 
     point.y; //==>0 
     x; //==>1 
     y; //==>1
    

    我们会发现不但我们希望的移动呢效果没有完毕,反而会多出两个全局变量。

    那么怎样解决呢?仅仅要要进入函数中的函数时将this保存到一个变量中,再运用该变量就可以。代码例如以下:

    var point = { 
     x : 0, 
     y : 0, 
     moveTo : function(x, y) { 
          var that = this; 
         // 内部函数
         var moveX = function(x) { 
         that.x = x; 
         }; 
         // 内部函数
         var moveY = function(y) { 
         that.y = y; 
         } 
         moveX(x); 
         moveY(y); 
         } 
     }; 
     point.moveTo(1, 1); 
     point.x; //==>1 
     point.y; //==>1
    

    构造函数调用

    在javascript中自己创建构造函数时能够利用this来指向新创建的对象上。

    这样就能够避免函数中的this指向全局了。

     var x = 2;
      function test(){
        this.x = 1;
      }
      var o = new test();
      alert(x); //2
    

    apply或call调用

    这两个方法能够切换函数运行的上下文环境。也就是改变this绑定的对象。

    apply和call比較类似,差别在于传入參数时一个要求是数组。一个要求是分开传入。所以我们以apply为例:

    <pre name="code" class="html">var name = "window";
        
    var someone = {
        name: "Bob",
        showName: function(){
            alert(this.name);
        }
    };
    
    var other = {
        name: "Tom"
    };   
     
    someone.showName();		//Bob
    someone.showName.apply();    //window
    someone.showName.apply(other);    //Tom
    

    能够看到,正常訪问对象中方法时,this指向对象。

    使用了apply后,apply无參数时,this的当前对象是全局,apply有參数时,this的当前对象就是该參数。


    箭头函数调用

    这里须要补充一点内容。就是在下一代javascript标准ES6中的箭头函数的 this始终指向函数定义时的 this,而非运行时。我们通过一个样例来理解:

    var o = {
        x : 1,
        func : function() { console.log(this.x) },
        test : function() {
            setTimeout(function() {
                this.func();
            }, 100);
        }
    };
    
    o.test(); // TypeError : this.func is not a function
    

    上面的代码会出现错误,由于this的指向从o变为了全局。我们须要改动上面的代码例如以下:

    var o = {
        x : 1,
        func : function() { console.log(this.x) },
        test : function() {
            var _this = this;
            setTimeout(function() {
                _this.func(); 
            }, 100);
        }
    };
    
    o.test();
    

    通过使用外部事先保存的this即可了。这里就能够利用到箭头函数了。我们刚才说过,箭头函数的 this始终指向函数定义时的 this,而非运行时。所以我们将上面的代码改动例如以下:


    var o = {
        x : 1,
        func : function() { console.log(this.x) },
        test : function() {
            setTimeout(() => { this.func() }, 100);
        }
    };
    
    o.test();
    

    这回this就指向o了,我们还须要注意一点的就是这个this是不会改变指向对象的,我们知道call和apply能够改变this的指向,可是在箭头函数中是无效的。


    var x = 1,
        o = {
            x : 10,
            test : () => this.x
        };
    
    o.test(); // 1
    o.test.call(o); // 依旧是1
    

    这样就能够明确各种情况下this绑定对象的差别了。


    
    




  • 相关阅读:
    实验9: 静态路由和默认路由
    实验8:路由器IOS升级2
    实验7:交换机IOS升级
    实验6:路由器IOS升级
    实验5: IOS的升级与恢复
    实验4: 路由器的密码恢复
    实验3: DHCP 基本配置
    Linux用户的基本操作3 (组的基本管理,用户提权)
    拓展练习:(用户的基本管理及用户提权部分)
    linux用户的基本操作2 用户密码管理
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5272458.html
Copyright © 2011-2022 走看看