在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都可以是函數的上下文發生改變,那咱們來具體看看這記者之間的區別吧。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)只須要傳入一個參數便可。
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能有必定的幫助,若是有疑問你們能夠留言交流。