1. 程式人生 > >淺談JavaScript中的apply,call,bind的使用

淺談JavaScript中的apply,call,bind的使用

相信很多人在面試或者做面試題的時候都會碰到有關JavaScript中的apply,call以及bind的問題,所以在這裡我為大家簡單地介紹一下這三者之間的用法以及異同點。

首先是這三者之間的共同點,用一句話來概括就是:改變this的指向

看到這裡或許有人對於this還是有些不理解,那我就先花點時間講解一下js中的this,如果已經充分理解this的可以略過這部分,直接往下看。

1.什麼是this?

在學習this之前請記住一句話“this的最終指向的是那個呼叫它的物件”,下面我們通過幾個例子來好好理解這句話的含義。

    <script> 
        function init(){
            var a = 1;
            console.log(this.a);  //結果是undefined
            console.log("---------------");
            console.log(this);    //結果是window
        }
        init();
    </script>

結果如下圖:

上面那個函式中的console.log(this.a)執行的結果是undefined,從console.log(this)中可以看出來這個時候的init()函式中的this指向的是全域性物件window,這是因為上面程式碼中的init();就相當於window.init();也就是說呼叫init函式中的this指標的最終物件是window而不是init函式,所以才會出現上面的結果。

    <script>  
        var init = {
            a : 1,
            show: function () {
                    console.log(this.a);//結果為1
                    console.log("---------------");
                    console.log(this);//結果為init
            }
        }
        init.show();
    </script>

結果如下圖:

解釋一下上面的init為一個物件,而a和show都是物件init中的屬性,a為init中的變數,show則為init中的函式,可以看到這次的結果的this.a指向的是物件init中的a,this則是指向了物件init,其實上面程式碼中的init.show();也可以相當於window.init.show();,只是要記住“this指向的是最終呼叫它的那個物件”,無論是init.show();還是window.init.show();最終呼叫show中的this指標都是init物件。

2.apply,call,bind

剛剛講到了這三者的共同點是改變this的指向,具體是怎麼做的我們通過幾個例子來了解一下。

    <script>  
        var init = {
            a : 1,
            show: function () {
                    console.log(this.a);
                    console.log(this);
            }
        }
        var take = {
            a: 2
        }
        init.show();
        console.log('---------apply----------');
        init.show.apply(take);
        console.log('---------call----------');
        init.show.call(take);
        console.log('---------bind----------');
        init.show.bind(take)();
    </script>

結果如下圖:

解釋程式碼:可以看到物件take中沒有定義方法show,這個時候為了程式碼的簡潔性,防止重複程式碼,減少工作量,我們會選擇呼叫init中的show方法,但是show方法使用了this指標並且指向的是init物件,這個時候apply,call,bind就發揮了它們的作用;從上面程式碼我們可以發現這三者的使用方式都是先呼叫另外一個物件的方法後跟上apply,call,bind,而括號中則是你改變this指標後要指向的物件,上文中則是take物件。

細心的你觀看上面程式碼可能已經發現了這三者的一些區別,那就是bind後面多跟了一個括號,這是因為apply和call使用是立即執行函式,而bind則是返回一個函式,加上括號是讓它自執行一次。

但是這不是這三者之間的最大區別,它們之間最大的區別在於如果呼叫的函式帶參的時候傳參的方式不一樣,call方法是將引數一個一個傳進去,而apply則是將引數先變成陣列在以陣列形式傳進去,具體例子如下:

    <script>  
        var init = {
            age : 0,
            show: function (name,sex) {
                    console.log(name+"年齡是"+this.age+",性別是"+sex);
            }
        }
        var take = {
            age: 20
        }
        console.log('---------apply----------');
        init.show.apply(take,["lisa","女"]);  //以陣列形式傳參
        console.log('---------call----------');
        init.show.call(take,"jack","男");     //一個一個進行傳參
    </script>

放上結果圖:

至於bind與其他兩者的區別就是剛才提到的使用bind你得到的結果是一個函式你可以在後面加上一個括號手動呼叫它。