js中的this和函數的調用

this是什麼

this是一個關鍵字,指向調用該方法的對象。
this是在執行環境上下文中被指定好的,也就是在一個函數調用但是還沒有開始執行的時候設定好的。它和作用域在函數聲明的時候公共部分就設定好了不一樣,它是看,當這個函數作爲某個對象的方法調用時,誰調用了它,它就指誰。它取決於誰調用了它

在js權威指南中,函數的調用分爲四種情況:

  • 作爲函數
  • 作爲方法
  • 作爲構造函數
  • 通過它們的apply和call方法調用

純粹的函數調用

這種純粹的函數調用,通常指的環境是全局,this指向的是window(非嚴格模式),或者undefined(嚴格模式)。以下寫的都是非嚴格模式下的結果:

和變量不同,關鍵字this沒有作用域的限制,嵌套的函數不會從調用它的函數中繼承this,如果嵌套函數作爲函數調用,其this值不是全局對象就是undefined。

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

function test,雖然實際上是作爲了window這個對象的一個方法,相當於window.test();

 function test() {
        var func = function add(){
            alert(this);//window
        };
        func();
    }
    test();

函數add賦值給了func,此時的func也是函數類型,內容也就是賦值=後那一串。
func();其實也就是(function add(){
alert(this);//window
})();
所以這裏,還是通過通過的函數調用,所以這裏的this也仍然是window。

https://www.ibm.com/developerworks/cn/web/1207_wangqf_jsthis/index.html
中看到這個例子也是類似的,也想了一會才明白:

var point = { 
x : 0, 
y : 0, 
moveTo : function(x, y) { //這個函數是作爲moveTo的方法而被調用的,this指向moveTo
    // 內部函數
    var moveX = function(x) { //這個函數是和上面的add相似,都是相當於是在全局下定義的,沒有作爲其他對象的方法,所以下面這兩個this指向的是全局。
    this.x = x;//this 綁定到了哪裏?
   }; 
   // 內部函數
   var moveY = function(y) { 
   this.y = y;//this 綁定到了哪裏?
   }; 

   moveX(x); 
   moveY(y); 
   } 
}; 
point.moveTo(1, 1); //調用函數moveTo
point.x; //==>0 
point.y; //==>0 
x; //==>1 
y; //==>1

這時候如果不希望這兩個moveX,moveY的this指向全局,可以使用that,詳細見上述地址。

作爲方法調用

下面又是另一種情況,函數做爲了其他對象的方法來調用:

 var test = {
        a:0,
        b: {
            c:7,
            fn:function(){
                alert(this.c);//7
            }
        }
    };
    window.test.b.fn();

那麼,這個時候又有一個問題,調用的對象又是指向誰呢?是window,還是test,還是b。

在函數中,彈出c的值是7,證明this訪問的是b中的內容,所以調用函數的對象它設定的是b。
註釋掉c:7,會發現會彈出undefined。
個人看到很多博客後得出一個結論:作爲方法調用時,它的this指向的是調用它的最近的那一個對象

作爲構造函數

如果函數或者方法調用之前帶有new關鍵字,它就構成構造函數調用

先了解一下new這個關鍵字來調用構造函數會發生什麼實際的步驟:
1)創建一個新對象
2)將構造函數的作用域賦給新對象(因此this就指向了這個新對象
3)執行構造函數中的代碼(爲這個新對象添加屬性)
4)返回新對象

先分析一下底下這個new:

function Person() {
        this.name = "zhuyi";
    }
    var a = new person();//沒有參數的話其實這對括號可以省略
    alert(a.name);//zhuyi

1)創建了一個新的空對象,比方我給這個空對象取名叫tmp(這個名字不存在,只是爲了便於看…)
2)將Person的作用域賦給tmp,也就是把this指向了tmp
3)執行Person中的代碼,這裏就是給tmp添加了name屬性
4)返回這個對象,然後這裏賦給了a

於是最後這一系列過程後,a就有了name屬性,也能alert出來了。

apply和call的調用

這兩個方法都能顯式指定this的值。
apply和call這兩個方法的第一個參數就代表着這個函數會被哪個對象來調用。那麼這個this就會被指定成這個對象。

var o = {};
    function person() {
        this.name = "zhuyi";
    }
//   person.call(o); 
//   person.apply(o); 
    alert(o.name);//undefined

新建了個空對象o,想用person作爲對象o的方法來調用,這時候,使用call和apply都可以做到,將對象o當成他們的第一個參數傳入,這時候,person就是o的一個方法,此時這個person函數的this都被設定爲指向o,那麼o.name也自然能返回設定的值了。

當apply和call的第一個參數設置爲空,此時,this指向全局

    var o = {};
    var name = "L";
    function person() {
        alert(this.name) ;
    }
     o.test = person;//新建一個對象o,給它的方法test設置爲person這個函數
//    o.test.apply();  
//註釋下一行後,刪除上行註釋,結果彈出L
   o.test();//undefined
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章