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绑定对象的差别了。


    
    




  • 相关阅读:
    WPF Caliburn 学习笔记(五)HelloCaliburn
    MSDN 教程短片 WPF 20(绑定3ObjectDataProvider)
    MSDN 教程短片 WPF 23(3D动画)
    比赛总结一
    HDU3686 Traffic Real Time Query System
    HDU3954 Level up
    EOJ382 Match Maker
    UESTC1565 Smart Typist
    HDU3578 Greedy Tino
    ZOJ1975 The Sierpinski Fractal
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5272458.html
Copyright © 2011-2022 走看看