使用call、apply和bind解決js中煩人的this,事件綁定時的this和傳參問題

一、什麼是this

在JavaScript中this能夠是全局對象、當前對象或者任意對象,這徹底取決於函數的調用方式,this 綁定的對象即函數執行的上下文環境(context)。數組

爲了幫助理解,讓咱們來一塊兒看一段代碼:閉包

// 做爲對象方法調用
var test = {
    a : 5,
    b : 6,
    sum : function () {
        return this.a + this.b;     // 此處this = test
    }
}
alert(test.sum());     // 11

做爲對象調用時this很容易理解,this等價於sum的調用者即上訴的test對象,若是做爲函數調用時this=?app

// 做爲函數調用
a = 4;
b = 3; function sum(){ return this.a + this.b; // 此處this = window } alert(sum()); // 7

此時函數sum是作爲window對象的一個全局函數,所以sum的調用者爲window,即this = window。框架

var test = {
    a : 5,
    b : 6,
    sum : function (a,b) {
        function getA(a) {
            this.a = a;         // 在window上增長了一個全局變量a
            return this.a;     // 此處this = window
        }
        function getB(b){
            this.b = b;         //在window上增長了一個全局變量b
            return this.b;     // 此處this = window
        }
        return getA(a) + getB(b);
    }
}
alert(test.sum(4,3));  // 7
alert(a);              // 4     
alert(b);              // 3

 在這種狀況下,咱們但願getA() 和getB() 返回的值是test.a和test.b,可是此時閉包函數(即函數中的函數)getA和getB中this並不指向test的實例,該怎麼辦呢?咱們不妨試試下面的方法:函數

var test = {
    a : 5,
    b : 6,
    sum : function () {
        var self = this;    // 此處this = test的實例
        function getA() {
            return self.a;
        }
        function getB(){
            return self.b;
        }
        return getA() + getB();
    }
}
alert(test.sum());
alert(a);     // 此處報錯:a is not defined
alert(b);    // 此處報錯:a is not defined

在test對象的sum函數中用一個局部變量self來保存當前的this指針,這樣在閉包函數getA和getB中就能經過self變量獲取test實例的屬性了。學習

看起來這樣就可以解決閉包函數中this的問題了,可是,若是調用sum函數的並非test的實例呢,這個時候var self=this還能起到做用,獲取到test的實例嗎?this

 二、使用call、apply和bind改變函數執行時的上下文(this)

使用call、apply和bind都可以是函數的上下文發生改變,那咱們來具體看看這記者之間的區別吧。spa

call方法:.net

語法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]])指針

定義:調用一個對象的一個方法,以另外一個對象替換當前對象。

說明:call 方法能夠用來代替另外一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變爲由 thisObj 指定的新對象。

     若是沒有提供 thisObj 參數,那麼 Global 對象被用做 thisObj。

apply方法:

語法:apply([thisObj[,argArray]])

定義:應用某一對象的一個方法,用另外一個對象替換當前對象。

說明:若是 argArray 不是一個有效的數組或者不是 arguments 對象,那麼將致使一個 TypeError。

        若是沒有提供 argArray 和 thisObj 任何一個參數,那麼 Global 對象將被用做 thisObj, 而且沒法被傳遞任何參數。

bind方法:

語法:bind(thisArg[, arg1[, arg2[, ...]]])

定義:將接受多個參數的函數變換成接受一個單一參數。

說明:bind()方法所返回的函數的length(形參數量)等於原函數的形參數量減去傳入bind()方法中的實參數量(第一個參數之後的全部參數),由於傳入bind中的實參都會綁定到原函數的形參。

哎呀媽呀,講了那麼多理論的東西,我都暈了,仍是看看實際的例子:

var test = {
    a : 5,
    b : 6,
    sum : function (a,b) {
        var self = this;
        function getA() {
            return self.a;
        }
        function getB(){
            return self.b;
        }
        alert(a);
        alert(b);
        return getA() + getB();
    }
}
var obj = {a:2,b:3};
alert(test.sum.call(obj,4,5));      // 調用時self = this = obj,alert順序4,5,5
alert(test.sum.apply(obj,[6,7]));   // 調用時self = this = obj,alert順序6,7,5
var sum = test.sum.bind(obj,8);     // 此處返回一個只有一個參數的函數sum(b)
alert(sum(9));                      // 調用時self = this = obj,alert順序8,9,5

從上面的例子咱們能夠很清晰的看到call、apply和bind之間的區別。其中call和apply是差很少的,只是傳參的形勢不一樣(apply的第二個參數爲一個數組或arguments),他們都是直接直接執行函數;

而bind函數將test.sum簡化爲另外一個全局函數sum(b),sum(b)只須要傳入一個參數便可。

三、解決js中煩人的this

call、apply和bind均可以應用於繼承,在這裏再也不過多贅述,網上有不少這樣的例子,參考:http://blog.csdn.net/wyyfwm/article/details/46349071

而我想講一下這段時間我遇到的一些關於this比較頭疼的事情。

<button id="btn">煩人的this</button>
<script>
    var test = {
        isSum: true,
        sum: function (event, a, b) {
            if (this.isSum) {   // this = button,這個時候不會執行alert(a+b)
                alert(a + b);
            }
        }
    }
    var button = document.getElementById("btn");
    button.addEventListener("click", test.sum, false);
</script>

這裏咱們就能發現問題所在了,當ID爲btn的按鈕被點擊時會觸發test.sum函數,可是這個時候的this=button,並且參數a、b如何傳入呢?

這裏就可以使用bind函數了,將test.sum函數簡化爲另外一個新的函數,同時傳入參數a和b,咱們再看看下面的代碼:

<button id="btn">this</button>
<script>
    var test = {
        isSum: true,
        sum: function (a, b,event) {
            if (this.isSum) {  // 此處this=test,this.isSum = true
                alert(a + b);  // 9
            }
        }
    }
    var button = document.getElementById("btn");
    button.addEventListener("click", test.sum.bind(test,4,5), false);  // 此處test.sum.bind(test,4,5)返回一個新的函數function(event),
</script>

從上面的代碼咱們能夠看到test.sum.bind(test,4,5)返回一個新的函數function(event),test、四、5分別被綁定到test.sum的上下文、參數a、參數b中。
當ID爲btn的按鈕被點擊時會觸發test.sum函數,此時改函數中的this=test,a=4,b=5。

這樣就能夠解決事件綁定時的this以及傳參的問題了,包括如今經常使用js框架中的事件綁定,如jQuery、signals.min.js等等。

 

總結

好了,以上就是這篇文章的所有內容了,但願本文的內容對你們學習或者使用Javascript能有必定的幫助,若是有疑問你們能夠留言交流。

 

轉載需註明轉載字樣,標註原做者和原博文地址。

相關文章
相關標籤/搜索