2.1-this

參考書籍: Javascript設計模式與開發實踐(曾探)

JavaScript 的this總是指向一個對象,而具體指向哪個對象是在運行時基於函數的執行環境動態綁定的,而非函數被聲明時的環境。

不同情況下this的指向:

  1. 作爲對象的方法調用。
  2. 作爲普通函數調用。
  3. 構造器調用。
  4. Function.prototype.call 或Function.prototype.apply 調用。

1、 作爲對象的方法調用

當函數作爲對象的方法被調用時,this 指向該對象:

var obj = {
    a: 1,
    getA: function(){
        alert ( this === obj ); // 輸出:true
        alert ( this.a ); // 輸出: 1
     }
};

obj.getA();

2、作爲普通函數調用

當函數不作爲對象的屬性被調用時,也就是我們常說的普通函數方式,此時的this 總是指向全局對象。在瀏覽器的JavaScript 裏,這個全局對象是window 對象。

window.name = 'globalName';

var getName = function(){
    return this.name;
};

console.log( getName() ); // 輸出:globalName

或者:

window.name = 'globalName';

var myObject = {
    name: 'sven',
    getName: function(){
        return this.name;
    }
};

var getName = myObject.getName;
console.log( getName() ); // globalName

e.g.
//錯誤方法
window.id = 'window';

document.getElementById( 'div1' ).onclick = function(){
    alert ( this.id ); // 輸出:'div1'

    var callback = function(){
        alert ( this.id ); // 輸出:'window'
    }

    callback();
};

//正確方法:作爲變量的值保存
document.getElementById( 'div1' ).onclick = function(){

    var that = this; // 保存div 的引用

    var callback = function(){
        alert ( that.id ); // 輸出:'div1'
    }

    callback();
};

//在ECMAScript 5 的strict 模式下,這種情況下的this 已經被規定爲不會指向全局對象,而是undefined:

function func(){
    "use strict"
    alert ( this ); // 輸出:undefined
}

func();

3、構造器調用

除了宿主提供的一些內置函數,大部分JavaScript 函數都可以當作構造器使用。構造器的外表跟普通函數一模一樣,它們的區別在於 被調用的方式。當用new 運算符調用函數時,該函數總會返回一個對象,通常情況下,構造器裏的this 就指向返回的這個對象.

var MyClass = function(){
    this.name = 'sven';
};

var obj = new MyClass();
alert ( obj.name ); // 輸出:sven

但用new 調用構造器時,還要注意一個問題,如果構造器顯式地返回了一個object 類型的對象,那麼此次運算結果最終會返回這個對象,而不是我們之前期待的this:

var MyClass = function(){
    this.name = 'sven';

    return {    // 顯式地返回一個對象
        name: 'anne'
    }
};

var obj = new MyClass();
alert ( obj.name ); // 輸出:anne

如果 構造器不顯式地返回任何數據,或者是返回一個非對象類型的數據,就不會造成上述問題:

var MyClass = function(){
    this.name = 'sven'
    return 'anne'; // 返回string 類型
};

var obj = new MyClass();
alert ( obj.name ); // 輸出:sven

4、Function.prototype.call 或Function.prototype.apply 調用

跟普通的函數調用相比,用Function.prototype.call 或Function.prototype.apply 可以動態地改變傳入函數的this:

var obj1 = {
    name: 'sven',

    getName: function() {
        return this.name;
    }
};

var obj2 = {
    name: 'anne'
};

console.log( obj1.getName() );            // 輸出: sven
console.log( obj1.getName.call( obj2 ) ); // 輸出:anne
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章