JavaScript中this指向以及改變this指向

隴錦發表於2018-06-27

關於this指向

  • 如果一個函式中有this,但是它沒有被上一級的物件所呼叫,那麼this指向的就是window,這裡需要說明的是在js的嚴格版中this指向的不是
    window。
    var a="隴錦";
   function foo() {
     var a="掘金";
     console.log(this.a);
     console.log(this)
   };
   foo();
複製程式碼
  • 如果一個函式中有this,這個函式被上一級的物件所呼叫,那麼this指向的就是上一級的物件。
    var a="隴錦";
    var foo = {
        a:"掘金",
        fn:function(){
            console.log(this.a); 
        }
    };
    foo.fn();
複製程式碼
  • 如果一個函式中有this,這個函式中包含多個物件,儘管這個函式是被最外層的物件所呼叫,this指向的也只是它上一級的
    var a={
        b:"隴錦",
        c:{
            // b:"掘金",
            fn:function() {
            console.log(this.b);//undefined
            }
        }
    };
    a.c.fn();
複製程式碼
  • this指向永遠都是最後呼叫他的物件,可以對比一下前面的例子。這裡q被賦值為fn函式,執行q,他的this就會改變。
    var a={
        b:"隴錦",
        c:{
            fn:function() {
            console.log(this.b);
            console.log(this);
            }
        }
    };
    var q=a.c.fn;
    q();
複製程式碼

當 this 碰到 return

  • 如果返回值是一個物件,那麼this指向的就是那個返回的物件,如果返回值不是一個物件那麼this還是指向函式的例項。
        function fn() {
            this.b="隴錦";
            return {
                b:"掘金"
            };
        };
        var a=new fn;
        console.log(a.b);
複製程式碼
   function fn() {
               this.b="隴錦";
               function (){}
           };
           var a=new fn;
           console.log(a.b);
複製程式碼
  • 但需要注意的是,雖然null也是物件,但是在這裡this還是指向那個函式的例項,因為null比較特殊。
    function fn() {  
        this.b = '隴錦';  
        return null;
    }
    var a = new fn;  
    console.log(a.user); 
複製程式碼

如何改變this指向

  • 通過new:用變數a建立了一個Fn的例項(相當於複製了一份Fn到物件a裡面),此時僅僅只是建立,並沒有執行,而呼叫這個函式Fn的是物件a,
    那麼this指向的自然是物件a,那麼為什麼物件a中會有user,因為你已經複製了一份Fn函式到物件a中,用了new關鍵字就等同於複製了一份.
    function Fn(){
        this.b = "掘金";
    }
    var a = new Fn();
    console.log(a.b);
複製程式碼
  • call方法和apply方法
    • 每個函式都包含兩個非繼承而來的方法:call()方法和apply()方法。
    • 相同點:這兩個方法的作用是一樣的。都是在特定的作用域中呼叫函式,等於設定函式體內this物件的值,以擴充函式賴以執行的作用域。
     window.color = 'red';
     document.color = 'yellow';
    
     var s1 = {color: 'blue' };
     function changeColor(){
         console.log(this.color);
     };
     changeColor.call();         //red (預設傳遞引數)
     changeColor.call(window);   //red
     changeColor.call(document); //yellow
     changeColor.call(this);     //red
     changeColor.call(s1);       //blue
複製程式碼
     window.number = 'one';
     document.number = 'two';
    
     var s1 = {number: 'three' };
     function changeColor(){
        console.log(this.number);
     };
     changeColor.apply();         //one (預設傳參)
     changeColor.apply(window);   //one
     changeColor.apply(document); //two
     changeColor.apply(this);     //one
     changeColor.apply(s1);       //three
複製程式碼
  • 不同點:接收引數的方式不同
    • apply()方法 接收兩個引數,一個是函式執行的作用域(this),另一個是引數陣列。
      • 語法:apply([thisObj [,argArray] ]);,呼叫一個物件的一個方法,2另一個物件替換當前物件。
    • 說明:如果argArray不是一個有效陣列或不是arguments物件,那麼將導致一個TypeError,如果沒有提供argArray和thisObj任何一個引數,那麼Global物件將用作thisObj。
    • call()方法 第一個引數和apply()方法的一樣,但是傳遞給函式的引數必須列舉出來。
      • 語法:call([thisObject[,arg1 [,arg2 [,...,argn]]]]);,應用某一物件的一個方法,用另一個物件替換當前物件。
      • 說明: call方法可以用來代替另一個物件呼叫一個方法,call方法可以將一個函式的物件上下文從初始的上下文改變為thisObj指定的新
        物件,如果沒有提供thisObj引數,那麼Global物件被用於thisObj。
 function add(c,d){
        return this.a + this.b + c + d;
    }

    var s = {a:1, b:2};
    console.log(add.call(s,3,4)); // 1+2+3+4 = 10
    console.log(add.apply(s,[5,6])); // 1+2+5+6 = 14 
複製程式碼
  • bind方法
    var a = {
        user:"掘金",
        fn:function(){
            console.log(this.user);
        }
    };
    var b = a.fn;
    b.bind(a);  //程式碼沒有被列印
複製程式碼
  • 我們發現程式碼沒有被列印,因為bind方法返回的是一個修改過後的函式。
    var a = {
        user:"掘金",
        fn:function(){
            console.log(this.user);
        }
    }
    var b = a.fn;
    var c = b.bind(a);
    console.log(c); //此時會吧函式列印出來
    
複製程式碼
  • 輸出user
    var a = {
        user:"掘金",
        fn:function(){
            console.log(this.user); //掘金
        }
    };
    var b = a.fn;
    var c = b.bind(a);
    c();
複製程式碼
  • 同樣bind也可以有多個引數,並且引數可以執行的時候再次新增,但是要注意的是,引數是按照形參的順序進行的。
    var a = {
        user:"掘金",
        fn:function(e,d,f){
            console.log(this.user); //掘金
            console.log(e,d,f); //10 1 2
        }
    };
    var b = a.fn;
    var c = b.bind(a,10);
    c(1,2);
複製程式碼
  • call和apply都是改變上下文中的this並立即執行這個函式,bind方法可以讓對應的函式想什麼時候調就什麼時候呼叫,並且可以將引數在
    執行的時候新增,這是它們的區別

參考部落格:追夢子blog http://www.cnblogs.com/pssp/

內容如有錯誤,歡迎指正。文章只寫給需要的人,大牛忽略。

相關文章