javascript
this
基礎
call
apply
javascript
Javascript函數中的this關鍵字的行爲相比其餘語言有不少不一樣。在Javascript的嚴格模式下和非嚴格模式下也略有不一樣。html
在大多數狀況下,函數的調用方式決定了this的值。this不能在執行期間被賦值,在每次函數被調用時this的值也會不一樣。ES5增長了bind方法,能夠在不對函數進行調用的狀況下傳入this值。java
在全局上下文中(在任何函數體外部),this指代全局對象,不管是否在嚴格模式下。web
console.log(this.doucment === document) //true //In web browsers, the window object is also the global object: console.log(this === window); //true this.a = 37; console.log(window.a); //37
在函數內部, this的值取決於函數是如何調用的。chrome
function f1() { return this; } f1() === window; //global object
在這個例子中,this的值不是由函數調用設定。由於代碼不運行在嚴格模式下,this的值始終是一個對象且默認爲全局對象。express
function f2() { "use strict"; return this } f2() === undefined; //return undefined
在嚴格模式下,this的值根據執行時的上下文,this所保存的值決定。若爲定義,this還是undefined, 它可能被設置爲任何的值,好比null,42或者是 " I'am not this "。瀏覽器
在第二個例子中,this的值應該是undefined。由於f2被調用時未基於任何對象(e.g.window.f2())。這個功能並未在全部第一次開始支持嚴格模式的瀏覽器中都獲得普遍支持,在不支持的瀏覽器中,仍然返回window,好比chrome。app
當一個函數做爲一個對象的方法被調用,它的this會被設置爲調用該方法的對象。
在下面的例子中,當o.f()被調用,function內部的this會綁定到這個object。函數
var o = {}; o.prop = 37; o.f = function() { return this.prop; }; console.log(o.f()); //37
注意,如何調用或者在何處定義這個函數並不影響this的行爲,在前一個例子中,咱們在定義的object中爲成員f添加了一個匿名函數,然而,咱們能
更簡便的先定義這些函數而後再將其附屬到o.f上。這樣作this的行爲也是一致。ui
var o = {prop:37}; function independent(){ return this.prop; } o.f = independent; console.log(o.f()); //logs 37
這個例子只有o對象中的f纔會令這個函數被調用。
一樣的,this綁定只會被最當前的引用所決定。在接下來的例子中,當咱們調用這個function,把它看成o.b對象的g方法調用。在執行中,this會附屬到o.b上。這個對象自己做爲o的成員沒有結果,其返回結果就是當前引用。
以下例:
o.b = {g: independent, prop:37} console.log(o.b.g()); //返回37
只要方法是定義在對象的原型鏈中上面的調用一樣的仍然正確,若是方法在一個對象的原型鏈中,this對象指向調用這個方法的對象,就像這個方法存在於這個對象中同樣。
var o = { f:function(){return this.a + this.b;} } var p = Object.create(o); p.a = 1; p.b = 5; console.log(p.f()); //6
在此例中,p對象並無它本身的實例f屬性,它繼承於原型鏈。可是沒有關係f能在o對象中找到;查找以一個p.f的引用開始,所以這個function中的this取對象p的引用值。也就是說,當f函數做爲p的對象被調用,它的this指向p。這是Javascript原型繼承中很是有趣的特徵。
當方法被getter或者setter調用一樣的概念仍然成立,當對象的屬性被set或者是gotten時,它的getter或者setter函數中的this對象會被綁定到當前對象。
function modulus(){ return Math.sqrt(this.re*this.re + this.im*this.im); } var o = { re : 1, im : -1, get phase(){ return Math.atan2(this.im,this.re); } }; Object.defineProperty(o,'modulus',{get: modulus,enumerable: true,configurable:true}); console.log(o.phase,o.modulus); //返回-7.86 1.414
當函數做爲構造器(使用new關鍵詞),它的this綁定爲新構造的對象。
注意:固然默認的構造器返回的this對象爲當前調用對象,它能被當前對象中return的新對象所取代(若是對象的返回值不是對象,那麼this仍指向當前對象)。
/*注意中示例*/ var o = { a : 12, f : function(){ return this.a; } }; var p = { a : 21, f : function(){ return o.f(); } }; console.log(p.f()); //返回12
構造器示例
/* * Constructors work like this: * * function MyConstructor(){ * // Actual function body code goes here. Create properties on |this| as * // desired by assigning to them. E.g., * this.fum = "nom"; * // et cetera... * * // If the function has a return statement that returns an object, that * // object will be the result of the |new| expression. Otherwise, the * // result of the expression is the object currently bound to |this| * // (i.e., the common case most usually seen). * } */ function C(){ this.a = 37; } var o = new C(); console.log(o.a); //返回37 function C2(){ this.a = 38; return {a:38}; } o = new C2(); console.log(o.a); //返回38
在上一個例子中(c2),由於有一個對象在構建中返回,因此this對象綁定到了返回的對象上。
在function內部使用this關鍵詞時,它的值能夠在使用call或apply(全部的function對象都繼承自Function.prototype)調用時綁定爲該函數中傳入的對象。
function add(c,d) { return this.a + this.b + c + d; } var o = { a : 2, b : 2 } console.log(add.call(o,2,2)); //返回8 console.log(add.apply(o,[2,4])); //返回10
ECMAScript 5介紹 Function.prototype.bind.調用f.bind(someObject).建立一個新的function擁有相同的內容和做用域,好比f,可是this對象仍然出如今原來的function中,在新的function中他仍然永久的被綁定在第一個bind的參數(someObj)上,好比下面的g函數,不管這個function被調用了多少次。
function f(){ return this.a; } var g = f.bind({a : "penouc"}); console.log(g()); var o = {a : 37,f : f, g : g}; console.log(o.f(),o.g());
當一個function被用做爲一個事件處理程序,它的this被設置爲當前的元素(一些瀏覽器並不遵循這個規則而是動態的添加方法好比使用addEventListener)。
//當元素被調用,其被激活爲藍色 function bluify(e) { console.log(this === e.target); console.log(this === e.currentTarget); this.style.backgroundColor = "#A5D9F3"; } //得到整個document的元素 var elements = document.getElementsByTagsName("*"); //當元素被點擊時元素被調用 for(var i = 0; i < elements.length; i++) { elements[i].addEventListener('click',bluify,false); }
當代碼被行內事件處理程序調用,它的this就是當前元素:
<button onclick="alert(this.tagName.toLowerCase());">Show this</button>
以上警告爲button。注意不管如何只有在存在外層代碼才設置爲這樣:
<button onclick="alert((function(){return this}}()));">Show inner this</button>
在這個例子中,內部的function的this並未設置所以返回爲window/global對象。