博客 / 詳情

返回

ES5 call,apply,bind方法總結(包括理解this的指向問題)

總結call,apply,bind方法的理解使用和區別。

call,apply,bind這三個方法在JavaScript中是用來改變函數調用的this指向。那麼改變函數this指向有什麼用呢?我們先來看一段代碼

var a= {
    name:'harden',
    fn:function () {
        console.log(this.name);
    }
}
var b = a.fn;
a.fn();//harden
b();//undefined

調用a.fn方法後得到了harden,但在b方法中我想得到harden,為什麼卻是undefined呢?原因是方法在執行的時候才能確定this到底指向誰,實際上this指向的是最終調用函數的對象。這裏當b執行時,實際是window調用了fn函數,那麼fn中的this就指向window。
在開始講call,apply,bind方法前,一起來總結一下this的指向問題。

理解JavaScript中的this指向問題。

總體來説this指向可以概括為一句話:this指向在函數的定義時是不確定的,只有函數執行時才能確定this到底指向誰,實際上this的最終指向的是那個調用它的對象。但是這個説法在函數被很多對象包裹的時候並不成立,請看下面例子。
簡單來説就是:誰(哪個對象)調用的這個函數,那麼這個函數中的this就指向這個對象。

例一

 function a(){
        var name= "harden";
        console.log(this.name); //undefined
        console.log(this); //Window
    }
    a();

因為this最終指向調用他的對象,在上述代碼中其實是widow觸發的這個方法,那麼this就指向window,window中並沒有定義a,那麼就打印出undefined。
例二:

var a = {
    name:'harden',
    fn:function() {
        console.log(this.name);//harden
        console.log(this);//指向a(可以自己跑一下)
    }
}
a.fn()

這裏的this指向a,因為這裏的fn函數是通過a.fn()執行的,那麼this自然指向a。
説到這我就有疑問了,如果我用 window.a.fn()執行函數,this不就指向window了嗎?然後並不是這樣的,請看下一個例子。補充一點:window是js的全局對象。
例三:

var a = {
    name:'harden',
    b:{
        name:'james',
        fn:function() {
            console.log(this.name);//james
            console.log(this);//指向b
        }
    }
}
a.b.fn()

我們看到最終是a調用的方法,那為什麼this會指向b呢?現在總結三句話,來完全理解this的指向問題:

情況一:如果一個函數中有this,但是它沒有被上一級的對象所調用,那麼this指向的就是window(除去嚴格模式外)。
情況二:如果一個函數中有this,這個函數有被上一級的對象所調用,那麼this指向的就是上一級的對象。
情況三:如果一個函數中有this,這個函數中包含多個對象,儘管這個函數是被最外層的對象所調用,this指向的也只是它上一級的對象,例子3可以證明。

  • 構造函數中的this:

     function Fn(){
           this.name = "harden";
       }
       var a = new Fn();
       console.log(a.name); //harden

這裏的a可以點出name,因為new關鍵字會改變this的指向。為什麼new關鍵字會改變this呢,我自己有兩種看法:
1.在new的過程中會創建一個實例對象,通過apply等方法 通過 Fn.apply({}) 使this指向這個空對象,最後把fn方法中的材料加工完後返回給a。

  • 當this遇到return的時候:

    function fn()  
       {  
           this.user = 'harden';  
           return {};  
       }
       var a = new fn;  
       console.log(a.user); //undefined
       
       function fn()  
       {  
           this.user = 'harden';  
           return function(){};
       }
       var a = new fn;  
       console.log(a.user); //undefined
       
       function fn()  
       {  
           this.user = 'harden';  
           return 1;
       }
       var a = new fn;  
       console.log(a.user); //harden
       
       function fn()  
       {  
           this.user = 'harden';  
           return undefined;
       }
       var a = new fn;  
       console.log(a.user); //harden
    

總結一下:如果返回值是一個對象,那麼this指向的就是那個返回的對象,如果返回值不是一個對象那麼this還是指向函數的實例。還有一點就是返回null,null也是對象,但是因為他的特殊性,返回後this還是指向函數本身的實例。理解JavaScript中的指向問題
理解完JavaScript中的指向問題,那麼回到正題:

call,apply,bind方法總結

1.call

a = { name: 'harden' }
function b () {
    console.log(this.name);
}
b.call(a);//harden
b()//undefined

b.call(a)用字面意思來講就是:把函數b添加到對象a的環境中,使函數中的this指向對象a。
call與apply不同的地方就是傳參不同。
2.apply

a = { name: 'harden' }
function b (data1,data2) {
    console.log(data1,data2);
}
b.call(a,'a1','a2');//a1 a2
b.apply(a,['a1','a2']);//a1 a2

3.bind

a = { name: 'harden' }
    function b () {
        console.log(this.name);
    }
    b.bind(a);//不會執行函數
    var aaa = b.bind(a);
    aaa()//harden

bind不會立即調用函數,是把函數返回,bind通常用它來指定回調函數的this。
關於call, apply, bind方法的區別與內部實現

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.