我的理解+google翻譯。若有錯誤,請留言指正。原文來自MDN: thisjavascript
Javascript中一個函數的this關鍵字的行爲相對其它語言有些不一樣。在嚴格模式和非嚴格模式間也有區別。java
在大多數狀況下,this的值由函數如何調用來決定。this值不能在函數執行過程當中賦值設置,而且每次函數調用時this值可能也不相同。ES5經過添加bind方法設置函數的this值,不管函數如何被調用。(this值永久不變)web
全局執行環境中(函數外部),不管在與不在嚴格模式下this指向全局對象。chrome
console.log(this.document === document); //true //在web瀏覽器中,window對象便是全局對象: console.log(this === window); // true this.a=37; console.logn(window.a); //37
在函數內部,this值依賴於函數如何調用。express
function f2(){ "use strict";//使用嚴格模式 return this; } f2() === undefined;
在上面的例子中,this值沒有在函數調用的時候被設置。因爲代碼沒有在嚴格模式下,this值確定總會是默認爲全局對象。數組
function f2(){ "use strict";//使用嚴格模式 return this; } f2() === undefined;
嚴格模式下,this值保持在進入執行環境時設置的值。若是this值未定義,則爲undefined;this值也能被設置爲任意值:如null、42或"I am not this";瀏覽器
注意:在第二例子中,this值應爲undefined,由於f2函數被調用時沒有提供任何引用[原文:base],(例如:window.f2())。這一特性在某些瀏覽器初始支持嚴格模式時沒有實現,形成返回錯誤的對象:windowapp
當函數做爲對象方法調用時,該函數的this值設爲調用該方法的對象。ide
在下例中,當o.f()被調用,函數內部this綁定爲o對象(inside the function this is bound to the o object).函數
var o={ prop:37; f:function(){ return this.prop; } }; console.log(o.f());// 37
注意:this的這種特性不受其函數如何定義或函數的定義位置的影響。在上例,咱們把函數定義爲對象o的內部成員f。然而咱們也能夠輕易的先定義這個函數,後面再把它附加到o.f上,結果是同樣的。
var o ={prop:37}; function independent{ return this.prop; } o.f=independent; console.log(o.f());//37
這段代碼代表:函數的調用來自對象o的f方法;一樣,this的綁定只受最近參考成員的影響。在下面的例子裏,調用該函數的時候,則爲對象o.b的g方法。這次函數執行時,函數內的this指向o.b.事實上,與o.b對象是o對象的成員沒有任何關係,最近參考纔是重要的。
var o ={prop:37}; function independent{ return this.prop; } o.f=independent; o.b{prop:42,g:independent}; console.log(o.f());//37 console.log(o.b.g());//42
一樣的概念也適用於在原型鏈上某些地方定義方法。若是該方法定義在對象的原型鏈上,this指向調用該方法的對象。【假設該方法是對象的成員】
var o = {f:function(){return this.a + this.b}}; var p = Object.create(o); p.a=1; p.b=4; console.log(p.f());//5
在上面的例子中,對象o分配給變量p,p沒有本身的屬性f,p從其原型中繼承f屬性。原型中f屬性的查找最終會在對象o上以一個成員的身份找到;查找開始以p.f爲參考,因此函數內的this取值爲對象p。因爲f做爲p的方法被調用,this指向p,這Javascript原型繼承一個有意思的特性。
我的添加了一個Object.create()例子,方便自我解惑:詳情請參考MDN:Object.create()
o = Object.create(Object.prototype, {//對象內屬性對應於Object.defineProperties的第二個參數 // foo is a regular "value property" --foo是一個普通值屬性 foo: { writable:true, configurable:true, value: "hello" }, // bar is a getter-and-setter (accessor) property --bar是一個getter、setter存取屬性 bar: { configurable:false,//默認:false,屬性的類型能被修改或該屬性能夠被刪除時爲true enumerable:false,//默認:false,對象屬性枚舉屬性時顯示該屬性爲true //writable:false, //默認:false,當屬性值能經過賦值操做而改變時爲true //value:"hi",//與屬性相關聯的值。能夠是任何有效的JavaScript值(數字,對象,函數等)。 get: function() { return this.value || 10 },//以一個函數做爲getter方法的屬性,若是沒有指定函數則爲undined。返回其屬性值 set: function(value) {this.value=value}//以一個函數做爲setter方法的屬性,若是沒有指定函數則爲undined。接收新的參數值成爲屬性值 } }); console.log(o.bar);//10 o.bar="hi"; console.log(o.bar); //hi
bar定義中有兩行註釋,若是取消註釋符號,在Firefox下會報錯:不容許在指定get 或 set時 指定其value屬性或爲定義writable屬性。[writable爲true或false都會報錯]
一樣的概念再次適用於函數做爲getter方法或setter方法。函數用做getter或setter方法則其this綁定到已經設置set或set屬性的所屬對象。(原文: A function used as getter or setter has its this bound to the object from which the property is being set or gotten.)
function modulus(){ return Math.sqrt(this.re * this.re + this.im * this.im); } var o ={ re : 1, im : -1, get phase(){//ES5的寫法,仍是建議用__defineGetter__這種API比較好,ie7 8 不支持 return Math.atan2(this.im,this.re); }, set txt(value){ this.re=value.re; this.im=value.im; } }; Object.defineProperty(o,'modulus1',{get : modulus,enumerable : true,configurable : true});//ie7 不支持此方法 ie8 不支持get: console.log(o.phase,o.modulus1);// -0.78 1.414 o.txt={re:12,im:3};//o.txt({re:12,im:3});報錯:o.txt is not a function console.log(o.phase,o.modulus1);//0.24 12.36
ES5 的getter、setter方法在ie7 8上不支持,汗的沒汗了……
當函數經過new關鍵字作爲構造函數時,函數的this指向該構造函數實例化後的對象。
注意:構造函數默認返回的對象被this引用,構造函數也能夠返回其它對象。若是返回值不是一個對象,那麼返回默認this引用的對象。( 原文:while the default for a constructor is to return the object referenced by this
, it can instead return some other object (if the return value isn't an object, then the this
object is returned))
/* * 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 建立須要的屬性及賦值。如: * 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). * //若是構造函數經過return語句返回一個對象,這個對象將會經過new表達式返回的實際對象。 * //若是函數體內沒有return語句,則經過new表達式返回的對象爲當前this默認引用的對象(這也是咱們通常常見的狀況) * } */ function c(){ this.a=37; } var o = new c(); console.log(o.a);//37 function c2(){ this.a = 37; return {a:38}; } o = new c2(); console.log(o.a);//38
在c2函數中,由於在構造函數運行並返回了一個對象,this默認綁定的對象則被簡單的丟棄。(其實是使語句this.a = 37;成爲廢棄代碼。也沒有徹底被廢棄,由於它獲得運行,只是在沒有外部影響的狀況下而被排除。)
函數內使用this關鍵字,經過call或apply方法調用該函數時,this值被指定爲一個特定的對象,所有function繼承於Function.prototype(all functions inherit from Function.prototype)
function add(c,d){ return this.a + this.b + c + d; } var o ={a:1,b:3}; //第一個參數是一個對象做爲this,隨後的參數做爲函數調用參數 add.call(o,5,7); //1+3+5+7 = 16 //第一個參數是一個對象做爲this,第二個參數是一個數組,該數組成員作函數調用參數 add.apply(o,[10,20]);//1+3+10+20 = 34
ES5 添加Function.prototype.bind。調用f.bind(someObject)建立與f具備相同內容和做用域的新函數,但原來的函數中的this在新函數中永久指向bind方法第一個參數,無論該函數如何調用。
function f(){ return this.a; } var g = f.bind({a:"azerty"}); console.log(g()); //azerty var o ={a:37,f:f,g:g}; console.log(o.f(),o.g()); // 37,azerty
當function做爲事件處理函數,this指向觸發該事件的DOM元素。(有些瀏覽器不支持下面經過addEventListener方法爲監聽動態添加方法,如:IE)。
//做爲監聽器時 改變相關元素爲藍色 function bluify(e){ console.log(this === e.currentTarget); //一直爲true console.log(e.currentTarget); console.log(this === e.target); //當currentTarge和target爲同一對象時爲true console.log(e.target); this.style.backgroundColor="#A5D9F3"; //e.stopPropagation(); //阻止事件冒泡 } //獲取document下元素列表 var elements = document.body.getElementsByTagName('*'); //添加bluify方法做爲點擊事件監聽器,使元素被點擊後變爲藍色 for(var i = 0;i < elements.length; i++){ elements[i].addEventListener('click',bluify,false); }
上面的代碼在某個結構層疊在3層或以上的頁面下的控制檯中(firebug/google chrome console)運行一下,會表現出一種怪異現象,不管點哪一個元素,整個頁的背景所有變爲藍色。試着把代碼e.stopPropagation()的註釋取消掉,或審查下元素,就應該知道爲何了。還不懂?請搜索 javascript 事件冒泡 相關資料。
當代碼在內聯處理器中執行時,代碼中的this被設爲其上有事件監聽的DOM元素:
<button onclick="alert(this.tagName.toLowerCase());">Show this</button>
上面的警告彈出框顯示button。 Note however that only the outer code has its this set this way:【實在翻譯不出來了,將就的這麼翻譯吧:可是要注意,這種方式只有函數外面的代碼中的this值纔會被設置爲事件監聽DOM元素】
<button onclick="alert((function(){return this}()));">Show inner this</button>
這種狀況下,函數內部的this沒有被指定,因此該函數返回全局對象或window對象。(即非嚴格模式下調用代碼中的this沒有被指定時的默認對象)。
<
button onclick="alert(this.tagName.toLowerCase());functiong(){//代碼}">
<
/button
>
PS:用腦子裏的半吊子英語水平+google翻譯+有道翻譯 這三種工具耗時3天按我的理解翻譯出這篇文章。總算體會到了IT英語翻譯的苦悶之處,不過本身也算有了翻譯的經驗,小自豪一把。若有錯誤,請列位拍磚指正。謝謝!