概念性的概述this
當一個函數創建后,一個關鍵字this就隨之(在后臺)創建,它鏈接到一個對象,而函數正是在這個對象中進行操作。換句話說,關鍵字this可在函數中使用,是對一個對象的引用,而函數正是該對象的屬性或方法。
讓我們來看這個對象:
<!DOCTYPE html><html lang="en"><body><script> var cody = { living:true, age:23, gender:'male', getGender:function(){return cody.gender;} }; console.log(cody.getGender()); // logs 'male' </script></body></html>注意在函數getGender里,由于在cody對象內部,我們可以通過.來獲取gender屬性(也就是cody.gender)。也可以用this來獲取cody對象,因為this正是指向cody對象。
<!DOCTYPE html><html lang="en"><body><script> var cody = { living:true, age:23, gender:'male', getGender:function(){return this.gender;} }; console.log(cody.getGender()); // logs 'male' </script></body></html>this.gender中this指向cody對象,而getGender函數可以操作cody對象。
關于this的主題可能有點讓人感到困惑,其實不必如此。僅記住,通常,this指向的對象正是包含函數的對象,而不是函數本身(當然也有例外,例如采用關鍵字new或者call()和apply())。
重要提示
- 關鍵字this就像其他的變量,唯一不同就是你不能更改它。
- 不同于傳給函數的其他參數和變量,在調用函數的對象中,this是一個關鍵字(而不是屬性)。
如何確定this的值?
this傳遞給所有的函數,它的值取決于函數運行時何時被調用。這里請注意,因為這是你需要記住的一個很特別的地方。
下面的代碼中myObject對象有個屬性sayFoo,它指向函數sayFoo。當在全局域中調用sayFoo函數時,this指向window對象。當myObject調用函數時,this指向的是myObject。
因為myObject有個叫foo的屬性,在這里被使用。
<!DOCTYPE html><html lang="en"><body><script> var foo = 'foo'; var myObject = {foo: 'I am myObject.foo'}; var sayFoo = function() { console.log(this['foo']); }; // give myObject a sayFoo property and have it point to sayFoo function myObject.sayFoo = sayFoo; myObject.sayFoo(); // logs 'I am myObject.foo' 12 sayFoo(); // logs 'foo' </script></body></html>很清楚,this的值取決于函數什么時候被調用。myObject.sayFoo和sayFoo都指向同樣的函數,但sayFoo()調用的上下文不同,this的值也就不同。下面是類似的代碼,head對象(window)顯式使用,希望對你有用。
<!DOCTYPE html><html lang="en"><body><script> window.foo = 'foo'; window.myObject = {foo: 'I am myObject.foo'}; window.sayFoo = function() { ! console.log(this.foo); }; window.myObject.sayFoo = window.sayFoo; window.myObject.sayFoo(); window.sayFoo(); </script></body></html>確保當你有多個引用指向同一個函數的時候,你清楚的知道this的值是隨調用函數的上下文的不同而改變。
重要提示
- 除了this以外的所有變量和參數都屬于靜態變量范圍(lexical scope)。
在嵌入函數內this指向head對象
你可能想知道在嵌入在另外一個函數的函數中使用this會發生什么事。不幸的是在ECMA 3中,this不遵循規律,它不指向函數屬于的對象,而是指向head對象(瀏覽器的window對象)。
在下面的代碼,func2和func3中的this不再指向myObject,而是head對象。
<!DOCTYPE html><html lang="en"><body><script> var myObject = { func1:function() { console.log(this); //logs myObject varfunc2=function() { console.log(this); //logs window, and will do so from this point on varfunc3=function() { console.log(this); //logs window, as it's the head object }(); }(); } }; myObject.func1(); </script></body></html>然而在ECMAScript 5中,這個問題將會得到修正。現在,你應該意識到這個問題,尤其是當你將一個函數的值傳遞到另一個函數時。
看看下面的代碼,將一個匿名函數傳給foo.func1,當在foo.func1中調用匿名函數(函數嵌套在另一個函數中),匿名函數中this將會指向是head對象。
<!DOCTYPE html><html lang="en"><body><script> var foo = { func1:function(bar){ bar(); //logs window, not foo console.log(this);//the this keyword here will be a reference to foo object } }; foo.func1(function(){console.log(this)}); </script></body></html>現在你不會忘了,如果包含this的函數在另一個函數中,或者被另一個函數調用,this的值將會指向的是head對象(再說一次,這將在ECMAScript 5中被修正。)
解決嵌套函數的問題
為了使this的值不丟失,你可以在父函數中使用一個作用域鏈(scope chain)來保存對this進行引用。下面的代碼中,使用一個叫that的變量,利用它的作用域,我們可以更好的保存函數上下文。
<!DOCTYPE html><html lang="en"><body><script> var myObject = { myProperty:'Icanseethelight', myMethod:function() { var that=this; //store a reference to this (i.e.myObject) in myMethod scope varhelperFunctionfunction(){//childfunction var helperFunction function() { //childfunction //logs 'I can see the light' via scope chain because that=this console.log(that.myProperty); //logs 'I can see the light' console.log(this); // logs window object, if we don't use "that" }(); } } myObject.myMethod(); // invoke myMethod </script></body></html>控制this的值
this的值通常取決于調用函數的上下文(除非使用關鍵字new,稍后會為你介紹),但是你可以用apply()或call()指定觸發一個函數時this指向的對象,以改變/控制this的值。用這兩種方法就好像再說:“嘿,調用X函數,但讓Z對象來作this的值。”這樣做,JavaScript默認的this的值將被更改。
下面,我們創建了一個對象和一個函數,然后我們通過call()來觸發函數,所以函數中的this指向的是myOjbect。在myFunction函數中的this會操作myObject而不是head對象,這樣我們就改變了在myFunction中this指向的對象。
<!DOCTYPE html><html lang="en"><body><script> var myObject = {}; var myFunction = function(param1, param2) { //setviacall()'this'points to my Object when function is invoked this.foo = param1; this.bar = param2; console.log(this); //logs Object{foo = 'foo', bar = 'bar'} }; myFunction.call(myObject, 'foo', 'bar'); // invoke function, set this value to myObject console.log(myObject) // logs Object {foo = 'foo', bar = 'bar'} </script></body></html>在上面的例子,我們用了call(),apply()也可適用于同樣用法,二者的不同之處在于參數如何傳給函數。用call(),參數用逗號分開,而用apply(),參數放在一個數組中傳遞。下面是同樣的代碼,但是用apply()。
<!DOCTYPE html><html lang="en"><body><script> var myObject = {}; var myFunction = function(param1, param2) { //set via apply(), this points to my Object when function is invoked this.foo=param1; this.bar=param2; console.log(this); // logs Object{foo='foo', bar='bar'} }; myFunction.apply(myObject, ['foo', 'bar']); // invoke function, set this value console.log(myObject); // logs Object {foo = 'foo', bar = 'bar'} </script></body></html>在自定義構造函數中用this
當函數用關鍵字new來觸發,this的值 主站蜘蛛池模板: 朝阳县| 建瓯市| 沅江市| 上蔡县| 江永县| 安陆市| 普陀区| 中宁县| 阳春市| 岱山县| 玉林市| 延吉市| 左贡县| 抚宁县| 喀喇沁旗| 寿光市| 金昌市| 红河县| 琼结县| 英山县| 博爱县| 石城县| 清流县| 夏河县| 万年县| 昭通市| 额尔古纳市| 佳木斯市| 军事| 灌云县| 双桥区| 临沭县| 昆明市| 伊宁市| 习水县| 新田县| 泸定县| 铁岭县| 绥宁县| 揭东县| 林周县|