this指向 最簡單的兩種!

原文地址:http://www.zhangyunling.com/?p=251



    在我們剛剛使用JS時,不知道您是否因爲一些東西而思路直接混亂的情況,反正我是有過,曾經有段時間,我是儘量在所有能不使用this的地方,不去使用this,因爲這個傢伙總是讓我不知道,它在一些地方,到底是代表的什麼含義,現在,自認爲有了一些認識,所以也敢於使用這個變量了,所以就有了本篇文章。
概述

首先有一點要先明確,那就是this是一個引用類型,也就是說,它是一個對象。OK,概述結束。
基礎示例

首先,讓我們先看下,this到底是指向的哪些對象呢?那就先看一些例子:

   
function testCallback(){
        if(this === window){
            console.log("this === window");
        }else if(this === document){
            console.log("this === document");
        }else if(this === a){
            console.log("this === a");
        }
    }
    testCallback(); //this===window
    document.onclick = testCallback; //this === document
    var a = {};
    a.callback = testCallback;
    a.callback(); //this === a


上述三種最簡單的情況,應該也算是我們最常見的了吧。說是三種,其實也只能算是兩種吧,因爲document.onclick和a.callback的兩種,其實質是相同的,只是對象名和屬性名是不同的。

所以,我們可以先根據上面的情況,把this的指向,定義爲兩種:

1:一種是如果顯示的在一個對象上直接調用了一個方法,那麼其中的this就是指向這個顯示的對象。

2:第二種是,如果沒有顯示的調用的話,比如之前代碼中,直接使用testCallback()執行函數,那麼其中的this,就是指向window對象的。

爲什麼沒有顯示的對象調用時,this是指向window對象呢?記得我們在最初學習JS時有過這樣的描述吧,如果沒有使用var定義一個變量,即便是在局部作用域定義,這也是一個全局變量,而全局變量是會被添加到window對象中,作爲其中的一個屬性的,所以,之前的testCallback方法,其實是存在於window對象中的一個方法。所以,這裏不算是顯示的調用,但是如果把這種調用方法寫的完全的話,應該是window.testCallback()的寫法,所以,按照顯示調用的說法,也是正確的。

OK,上述的兩種說法,只是在我們平常的一些基本的寫法的,比如,在使用DOM2級事件綁定中,回調函數的內部,其this的指向,就和我們常說的有些區別。

例如:

 
  function testCallback(){
        if(this === window){
            console.log("this === window");
        }else if(this === document){
            console.log("this === document");
        }
    }
    function addEvent(obj,type,callback){
        if(obj.addEventListener){
            obj.addEventListener(type,callback,false);
        }else if(obj.attachEvent){
            obj.attachEvent("on"+type,callback);
        }else{
            var fn = obj["on"+type];
            obj["on"+type] = function(){
                fn && fn();
                callback();
            }
        }
    }
    addEvent(document,"click",testCallback);



這個時候,當你點擊當前頁的任意位置,都可以觸發該事件,這時你會發現些什麼問題呢?這個時候,你就會發現一個問題,在IE9+的瀏覽器中,當你點擊時,會出現"this === document"的顯示,這個時候,也就是,我們這個事件在哪個HTML對象上綁定,那麼回調函數中的this就是指向這個綁定的對象的,之前的代碼中,點擊事件是綁定在document對象上的,所以,this等於document是很正常的了,也是我們希望的結果。

而在IE9-的瀏覽器中,顯示的結果卻是“this === window”,這就導致了一個問題,那就是,我們並不能確認自己的代碼只會在IE9+的瀏覽器中運行,所以這個時候,就不能直接使用this進行處理,但是如果不使用this,獲取到對應的觸發元素,又有些麻煩(這裏只考慮原生的JS,不考慮框架中的實現),所以,爲了減少這種錯誤的情況出現,只能放棄使用this了。

前面之所以在IE9-的瀏覽器事件的回調函數中,this指向window的原因,也是因爲,在IE9-的瀏覽器中,HTML的DOM元素的對象,並不是繼承自Object對象的,所以和其他瀏覽器下,DOM元素的對象繼承自Object對象,是有很大的差距的。

只需要下面的一行代碼,既可以驗證DOM元素的對象是否繼承自Object對象。

    console.log(document instanceof Object);

練習一下

基礎的東西,暫時就能想到這麼些了,自我感覺應該也是差不多了,現在給幾個例子,看下是否能正確的理解到this的指向問題:

例子1,請看其中註釋處,分別打印出的結果是什麼:

 
   var a = {
        name:"zhang",
        sayName:function(){
            console.log("this.name="+this.name);
        }
    };
    var name = "ling";
    function sayName(){
        var sss = a.sayName;
        sss(); //this.name = ?
        a.sayName(); //this.name = ?
        (a.sayName)(); //this.name = ?
        (b = a.sayName)();//this.name = ?
    }
    sayName();



例子2:
    var sex = "male";
    var saySex = {
        sex:"female",
        saySex:function(){
            function getSex(){
                console.log("this.sex="+this.sex);
            }
            getSex();
        }
    }
    saySex.saySex(); //this.sex = ?
    var ccc = saySex.saySex;
    ccc();//this.sex = ?



例子3:該例和例2只有一點點變化:
    var sex = "male";
    var saySex = {
        sex:"female",
        saySex:function(){
            function getSex(){
                console.log("this.sex="+this.sex);
            }
            getSex.call(this);
            //與例2只有這個地方的變化
        }
    }
    saySex.saySex(); //this.sex = ?
    var ccc = saySex.saySex;
    ccc();//this.sex = ?



例4:

  
 var name = "ling";
    function sayName(){
        var a = {
            name:"zhang",
            sayName:getName
        };
        
        function getName(){
            console.log(this.name);
        }
        
        getName(); //this.name = ?
        a.sayName(); //this.name = ?
        getName.call(a);//this.name = ?
    }
    sayName();



例5(當點擊頁面時,就會觸發):

  
 var name = "ling";
    var obj = {
        name:"zhang",
        sayName:function(){
            console.log("this.name="+this.name);
        },
        callback:function(){
            var that = this;
            return function(){
                var sayName = that.sayName;
                that.sayName(); //this.name = ?
                sayName();//this.name = ?
            }
        }
    }
    function addEvent(obj,type,callback){
        if(obj.addEventListener){
            obj.addEventListener(type,callback,false);
        }else if(obj.attachEvent){
            obj.attachEvent("on"+type,callback);
        }else{
            var fn = obj["on"+type];
            obj["on"+type] = function(){
                fn && fn();
                callback();
            }
        }
    }
    addEvent(document,"click",obj.callback());



這裏,暫時就能想到這麼些使用的地方,其實也可以歸納一下:
首先,不管是函數最初定義在哪裏,它其中的this指向,只和這個函數的調用方法有關。

fn()這種寫法的this,肯定是指向window對象的。

obj.fn();這樣寫法的this,肯定是指向obj對象的。

這裏不考慮call和apply強行改變this指向的關係,
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章