js this指向練習題


this指向及應用

關於js中的this指向問題:有很多同學剛接觸js時,對this的指向問題很是迷惑,在有些不常見情況,往往搞不清到底指向誰。對此,我們只需記住一點:this始終指向調用它的對象。廢話少說,下面直接通過不同情況下的實例來說明其指向問題。
1、對象中的方法中的this,指向調用它的對象,即 b ,所以 this.a 的輸出結果是b對象中的a的值; 如果b對象中沒有a,則this.a的輸出結果是 undefined。

var o = {
    a: 10,
    b: {
        a: 12,
        fn: function(){
            console.log(this.a); // 輸出結果是 12
            console.log(this); // 輸出結果是 b 對象
        }
    }
}
//調用
o.b.fn(); 
var o = {
    a: 10,
    b:  {
        fn: function(){
            console.log(this.a); // undefined
            console.log(this);   // b對象
        }
    }
}
//調用
o.b.fn(); 

 

2、改變調用方法,不直接調用:改用賦值后調用,此時this的指向為window,所以this.a的輸出結果為 undefined,因為全局中沒有全局變量a。

var o = {
    a: 10,
    b: {
        a: 12,
        fn: function(){
            console.log(this.a); //undefined 若在對象o外定義a,則輸出的就是其在外定義的值(全局變量)
            console.log(this);   // window
        }
    }
}
var j = o.b.fn; //只是將b對象下的方法賦值給j,並沒有調用
j(); //調用,此時綁定的對象是window,並非b對象直接調用

 

3、在對象方法中調用時:

var point = { 
    x : 0, 
    y : 0, 
    moveTo : function(x, y) { 
        this.x = this.x + x; 
        this.y = this.y + y;
        console.log(this.x); // 1
        console.log(this.y); // 1
    } 
}; 
point.moveTo(1, 1)//this 綁定到當前對象,即 point 對象

 

4、作為函數調用時

function someFun(x) { 
    this.x = x; 
} 
someFun(5); //函數被調用時,this綁定的是全局對象 window,相當於直接聲明了一個全局變量x,並賦值為5
console.log(x); // x 已經成為一個值為 5 的全局隱式變量

更復雜一點的情況:如下所示,point對象中的x、y沒有被改變,並結果中多了兩個新的全局變量x,y,值都為1。根本原因是point對象下的moveTo方法中的moveX與moveX方法在調用時都是全局調用,綁定的對象都是window。

var point = { 
    x : 0, 
    y : 0, 
    moveTo : function(x, y) { 
       // 內部函數
       var moveX = function(x) { 
           this.x = x;
       }; 
       // 內部函數
       var moveY = function(y) { 
           this.y = y;
       };
       moveX(x); // 這里是全局調用
       moveY(y); 
    }; 
}; 
point.moveTo(1, 1); 
console.log(point.x); // 0
console.log(point.y); // 0

可以通過下面情況輸出結果說明:

var point = { 
         x : 0, 
         y : 0, 
         moveTo : function(x, y) { 
             this.x = x;
             console.log(this.x); // 1
             console.log(this);   // point對象

             // 內部函數
             var moveX = function(x) { 
                this.x = x;
             }; 
             // 內部函數
             var moveY = function(y) { 
                this.y = y;
             } 
             moveX(x); // 這里是全局調用
             moveY(y); 
         } 
    }; 
    point.moveTo(1, 1); 
    console.log(point.x); // 1
    console.log(point.y); // 0
    console.log(x); // 1
    console.log(y);// 1

像如上對象中函數方法所示,本意是改變point對象中的x、y的值,而非新建全局變量。所以可以通過以下方法避免上述情況:

var point = { 
         x : 0, 
         y : 0, 
         moveTo : function(x, y) { 

             var that = this; //內部變量替換

             // 內部函數
             var moveX = function(x) { 
                 that.x = x; 
                // this.x = x;
             }; 
             // 內部函數
             var moveY = function(y) { 
                 that.y = y;
                // this.y = y;
             } 
             moveX(x); //這里依然是全局調用,但是在給變量賦值時,不再是this指向,而是that指向,而that指向的對象是 point。
             moveY(y); 
         } 
    }; 
    point.moveTo(1, 1); 
    console.log(point.x); // 1
    console.log(point.y); // 1
    console.log(x) // 報錯 x is not defined
    console.log(y) //

另附將moveX、moveY由內部函數改為非內部函數后的一種情況示例:這種情況下moveX、moveY方法的調用時綁定在moveTo對象上的,因為moveTo對象一開始是沒有x、y變量的,所以執行 this.x = x、this.y = y之后,相當於在moveTo對象中新建了兩個變量。

var point = { 
         x : 0, 
         y : 0, 
         moveTo : { 
             // 內部函數
             moveX: function(x) {
                console.log(this) // {moveX: ƒ, moveY: ƒ}
                this.x = x;
             },
             // 內部函數
             moveY: function(y) { 
                this.y = y;
             }
         } 
    }; 
    point.moveTo.moveX(1); 
    point.moveTo.moveY(1);
    console.log(point.moveTo);  // {moveX: ƒ, moveY: ƒ, x: 1, y: 1}
    console.log(point.x); // 0
    console.log(point.y); // 0
    console.log(x) // x is not defined
    console.log(y) //

 

5、作為構造函數調用:

function Point(x, y){ 
       console.log(this); // point對象
       this.x = x; 
       this.y = y; 
       this.moveTo = function(x,y){
          this.x = x;
          this.y = y;
          console.log(this.x);//1 10
          console.log(this.y);//1 10
       }
    }
    var p1 =  new Point(0,0); //注意這種形式方法的調用及apply、call的使用

    var p2 = {
        x:0,
        y:0
    }
    p1.moveTo(1,1); 
    p1.moveTo.apply(p2,[10,10]);

    console.log(x);// x is not defined
    console.log(y);// 

6、this在不同場景中的指向
      ①匿名函數中的this指向全局對象

var a = 10;
var foo = {
    a: 20,
    fn: (function(){
        console.log(this); // window
        console.log(this.a); // 10
    })()
}

      ②setInterval和setTimeout定時器中的this指向全局對象

var a = 10;
var oTimer1 = setInterval(function(){
    var a = 20;
    console.log(this.a); // 10
    clearInterval(oTimer1);
},100);

      ③eval中的this指向調用上下文中的this

(function(){
    eval("console.log(this)"); // Window
})();
function Foo(){
    this.bar = function(){
        eval("console.log(this)"); // Foo
    }
}
var foo = new Foo();
foo.bar();

      ④apply和call中的this指向參數中的對象

var a = 10;
var foo = {
    a: 20,
    fn: function(){
        console.log(this.a);
    }
};
var bar ={
    a: 30
}
foo.fn.apply();//10(若參數為空,默認指向全局對象)
foo.fn.apply(foo);//20
foo.fn.apply(bar);//30

附:eval、apply、call方法的說明:
eval() 函數可計算某個字符串,並執行其中的的 JavaScript 代碼。
call 、apply 這個兩個函數的第一個參數都是 this 的指向對象,第二個參數的區別如下:
  call的參數是直接放進去的,第二第三第n個參數全都用逗號分隔,直接放到后面 obj.myFun.call(db,'params1', ... ,'paramsn' );
  apply的所有參數都必須放在一個數組里面傳進去 obj.myFun.apply(db,['params1', ..., 'paramsn' ]);
以上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM