程式扎記: [ JS 文章收集 ] JavaScript 的 self 和 this 使用小結

標籤

2014年7月3日 星期四

[ JS 文章收集 ] JavaScript 的 self 和 this 使用小結

來源自 這裡 
self 關鍵字介紹: 
這個非常簡單。我們知道,打開任何一個網頁,瀏覽器會首先創建一個窗口,這個窗口就是一個 window 對象,也是 js 運行所依附的全局環境對象和全局作用域對象。self 指窗口本身,它返回的對象跟window 對像是一模一樣的。也正因為如此,window 對象的常用方法和函數都可以用 self 代替window。舉個例子,常見的寫法如 “self.close();”,把它放在<a>標記中:“<a href="javascript:self.close();">關閉窗口</a>” ,單擊“關閉窗口”鏈接,當前頁面關閉。 

this 關鍵字介紹: 
在講this之前,看下面的一段代碼: 
  1. <html>  
  2. <body>   
  3. <script type = "text/javascript">   
  4.   function thisTest()   
  5.   {   
  6.       alert("thisTest being called!")  
  7.       this.textValue =  'this 的 dom 測試1' ;   
  8.       this.element = document.createElement('span');   
  9.       this.element.innerHTML =  this.textValue;   
  10.       this.element.style.color =  "blue" ;   
  11.       this.element.style.cursor =  "pointer" ;   
  12.       this.element.onclick=function(){alert( " 單擊我:" + this.textValue)};   
  13.   }     
  14.   thisTest.prototype.RenderDom   
  15.   =function()   
  16.   {   
  17.       alert("RenderDom being called!")  
  18.       document.body.appendChild(this.element);   
  19.   };          
  20.      
  21.   //thisTest.prototype.toString  
  22.   function toString()   
  23.   {   
  24.       alert("toString being called!")  
  25.       alert( " 單擊我:" + this.textValue);   
  26.   };   
  27.   var test =  new thisTest();   
  28.   test.RenderDom();   
  29.   // test.ToString();   
  30. </script>   
  31. </body>  
  32. </html>  
本來的目的是想在body中添加一個span元素,對於這個span元素,制定了它的字體顏色,懸浮在它上面的鼠標樣式和單擊觸發事件。問題就出現在它的單擊事件上(彈出"單擊我:undefined")。也許有人會說你丫傻呀,寫這麼多sb代碼還不就是為了實現下面這個東東嗎? 
  1. < span style ='cursor:pointer;color:blue;' onclick ="alert(this.innerHTML)" > this的dom測試</ span >  
你看多簡單直觀,而且還不容易出錯?!kao,我暈。我正要講的是您正在使用的 this.innerHTML中的 this 呀。 

this 到底指什麼? 
我們熟悉的c#有 this 關鍵字,它的主要作用就是指代當前對象實例(參數傳遞和索引器都要用到 this)。在 javascript 中,this 通常指向的是我們正在執行的函數本身,或者是指向該函數所屬的對象運行時)。常見使用方式有直接在dom元素中使用: 
  1. <input id ="btnTest" type ="button" value ="提交" onclick ="alert(this.value))" />  
對於 dom 元素的一個 onclick(或其他如onblur等)屬性,它為所屬的 html 元素所擁有,直接在它觸發的函數里寫 this, this 應該指向該 html 元素. 又如給dom元素註冊js函數: 
- 不正確的方式 
  1. <script type = " text/javascript ">   
  2.   function thisTest(){   
  3.   alert( this .value); // 彈出undefined, this在這裡指向??   
  4. }   
  5. </script>   
  6. < input id = "btnTest" type=" button" value = " 提交" onclick = "thisTest()" />  
onclick 事件直接調用 thisTest 函數,程序就會彈出 undefined。因為thisTest函數是在window對像中定義的,所以 thisTest 的擁有者作用域 windowthisTest  this 也是 window而 window 是沒有 value 屬性的,所以就報錯了

- 正確的方式 
  1. <input id=" btnTest " type="button" value="提交"  />   
  2.   
  3. <script type = " text/javascript">   
  4.   function thisTest(){   
  5.   alert( this .value);   
  6. }   
  7. document.getElementById( " btnTest " ).onclick = thisTest; // 給button的onclick事件註冊一個函數  
  8. </script>  
在前面的示例中,thisTest 函數定義在全局作用域(這裡就是 window 對象),所以 this 指代的是當前的 window 對象。而通過 document.getElementById("btnTest").onclick=thisTest; 這樣的形式,其實是將 btnTest 的 onclick 屬性設置為thisTest 函數的一個副本,在 btnTest 的 onclick 屬性的函數作用域內, this 歸 btnTest 所有, this 歸 btnTest, 也就指向了btnTest。 

另外類定義中使用 this 關鍵字再常見不過,看範例: 
  1. function thisTest()   
  2. {   
  3.       var tmpName =  'jeff wong' ;   
  4.       this.userName =  'jeff wong' ;   
  5. }   
  6.   
  7. var test =  new thisTest();   
  8. alert(test.userName == test.tmpName); // false   
  9. alert(test.userName); // jeff wong  
  10. alert(test.tmpName); // undefined  
分析一下結果,其實這裡的 this 和 c# 裡的是類似的。 

this 也可使用來為腳本對象添加原形方法. 理解這裡的前提是你必須了解js裡的原型概念:js 中對象的 prototype 屬性,是用來返回對象類型原型的引用的。所有 js 內部對像都有隻讀的 prototype 屬性,可以向其原型中動態添加功能 (屬性和方法),但該對像不能被賦予不同的原型。但是對於用戶定義的對象可以被賦給新的原型。看個簡單的範例: 
  1. // js的內部對象String,向其原型中動態添加功能(屬性和方法)   
  2. // 去掉字符串兩端的空白字符  
  3. String.prototype.Trim =  function () {   
  4.     return  this.replace( / (^\s+) |(\s+$) / g, "" );   
  5. }   
  6.   
  7. function thisTest()   
  8. {   
  9.       var tmpName =  '  jeff wong  ' ;   
  10.       this.userName =  '  jeff wong  ' ;   
  11. }   
  12. // 給用戶定義的對象添加原型方法  
  13. thisTest.prototype.ToString =  function ()   
  14. {   
  15.       alert( this.userName); // jeff wong(*有空格*)   
  16.       alert( this.userName.Trim()); // jeff wong (*無空格*)   
  17.       // alert(tmpName ); //腳本錯誤,tmpName未定義  
  18. }   
  19.   
  20. var test =  new thisTest();   
  21. test.ToString(); // 調用原型的ToString()   
  22.   
  23. function myTest(){   
  24.   this .userName =  '   test ' ;   
  25. }   
  26. var test1 = new myTest();   
  27. // test1.ToString(); //這裡暫時不支持調用 ToString() 方法  
  28.   
  29. // 用戶定義的對像被賦給新的原型  
  30. myTest.prototype =  new thisTest();   
  31. test1.ToString() ; // 調用原型的ToString()  
測試結果顯示,這裡的 this 指代的是被添加原形(方法或屬性)的類的實例. 

你也可以在函數的內部函數中使用 this 關鍵字. 這個你要是理解 作用域 和 閉包 (Closure),問題就迎刃而解。看最典型的範例: 
  1. function thisTest()   
  2. {   
  3.       this.userName =  ' outer userName ' ;   
  4.       function innerThisTest(){   
  5.         var userName = " inner userName " ;   
  6.         alert(userName); // inner userName   
  7.         alert( this.userName); // outer userName   
  8.       }   
  9.      return innerThisTest ;   
  10. }   
  11. thisTest()();  
thisTest() 調用內部的 innerThisTest 函數,形成一個閉包。innerThisTest 執行時,第一次彈出innerUserName,是因為 innerThisTest 函數作用域內有一個變量叫 userName,所以直接彈出當前作用域下變量的指定值;第二次彈出 outer userName 是因為 innerThisTest 作用域內沒有 userName 屬性(示例中的 this.userName),所以它向上一級作用域中找 userName 屬性,這次在thisTest 中找到(示例中的 this.userName= 'outer userName';),所以彈出對應值。 

最後一個用法是你可以通過 Function 的 call 和 apply 函數指定特定的 this. 這個指定來指定去,this就有可能造成“你中有我,我中有你”的局面,不想把自己弄暈了的話,了解一下就可以了。改變 this指定對像對於代碼維護也是一件很不好的事情. 範例代碼如下: 
  1. function myFuncOne() {   
  2.     this.p =  " myFuncOne- " ;   
  3.     this.A =  function (arg) {   
  4.         alert( this.p + arg);   
  5.     }   
  6. }   
  7.   
  8. function myFuncTwo() {   
  9.     this.p =  " myFuncTwo- " ;   
  10.     this.B =  function (arg) {   
  11.         alert( this.p + arg);   
  12.     }   
  13. }   
  14. function test() {   
  15.     var obj1 =  new myFuncOne();   
  16.     var obj2 =  new myFuncTwo();   
  17.     obj1.A( " testA " );                        // 顯示myFuncOne-testA   
  18.     obj2.B( " testB " );                         // 顯示myFuncTwo-testB   
  19.     obj1.A.apply(obj2, [ " testA " ]);           // 顯示myFuncTwo-testA,其中[ testA”]是僅有一個元素的數組  
  20.     obj2.B.apply(obj1, [ " testB " ]);           // 顯示myFuncOne-testB,其中[ testB”]是僅有一個元素的數組  
  21.     obj1.A.call(obj2, " testA " );              // 顯示myFuncTwo-testA   
  22.     obj2.B.call(obj1, " testB " );              // 顯示myFuncOne-testB   
  23. }  
到這裡,對於開篇中的 span 彈出 undefined 的問題你是不是已經豁然開朗?如果你還在懵懂中,給個可有可無的提示:當前的這個 span 元素有沒有 textValue 屬性啊!?

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!