2012-03-15 79 views
4

示例代碼JavaScript的問題:關於關鍵字這個

<!DOCTYPE html> 
<html> 
<head> 
    <title>test</title> 

    <script language="javascript" type="text/javascript"> 

    function init() { 
     var nodeList = document.getElementsByTagName("a"); 
     var nodeArr = []; 
     for(var i = 0; i < nodeList.length; i++) // Copy NodeList to Array 
      nodeArr.push(nodeList[i]); 
     for(var i = 0; i < nodeArr.length; i++) // Loop over array 
      if(nodeArr[i].className == "clickLink") 
       nodeArr[i].onclick = clickLink2; // Attach event function 
    } 

    window.onload = init; //Attach event function 

    function clickLink2() { 
     console.log("this: " + this); //Prints window URL in href 
     console.dir(this); //show attributes of anchor  
     console.log(this.name); // Prints name attribute 
    } 


    function clickLink(elem) { 
     console.log("this: " + this); //Prints [object Window] 
     console.dir(this); // Shows attributes, etc. al of [object Window] 
     console.log("name: " + elem.name);  
    } 
    </script> 

    </head> 

    <body> 

    <!-- inline --> 
    <a href="#" name="blah1" onclick="clickLink(this); return false;">Test 1</a> 
    <a href="#" name="blah2" onclick="clickLink(this); return false;">Test 2</a> 
    <a href="#" name="blah3" onclick="clickLink(this); return false;">Test 3</a> 
    <a href="#" name="blah4" onclick="clickLink(this); return false;">Test 4</a> 


    <hr/> 
    <!-- not inline --> 
    <a href="#" name="blah5" class="clickLink">Test 5</a> 
    <a href="#?t" name="blah6" class="clickLink">Test 6</a> 
    <a href="#" name="blah7" class="clickLink">Test 7</a> 
    <a href="#" name="blah8" class="clickLink">Test 8</a> 

    </body> 

    </html> 

我沒有在Firefox的測試,用Firebug查看控制檯輸出。

現在我想知道:

  1. 爲什麼clickLink沒有指窗口對象?
  2. 爲什麼這個clickLink2打印到控制檯作爲鏈接的href值?
  3. 有沒有更好的方法將這個傳遞給這樣一個不顯眼的附件?你怎麼能確定這個指的是什麼?

OK,所以我把碎片從答案在這裏,發現這在某些瀏覽器有點古怪。此外,將功能分配給onclick與附加功能不同(但不幸的是,並非所有IE版本都支持addEventListenerattachEvent)。由於某種原因,舊IE瀏覽器也使這個內部的一個事件觸發器函數仍然指向窗口對象而不是調用者。所以我用event.srcElement。下面是一些新的示例代碼:

<!DOCTYPE html> 
<html> 
<head> 
    <title>test</title> 

<script language="javascript" type="text/javascript"> 

function init() { 
    var nodeList = document.getElementsByTagName("a"); 
    var nodeArr = []; 
    for(var i = 0; i < nodeList.length; i++) // Copy NodeList to Array 
     nodeArr.push(nodeList[i]); 
    for(var i = 0; i < nodeArr.length; i++) // Loop over array 
    if(nodeArr[i].className == "clickLink") { 

     var a = nodeArr[i]; 

     if (a.addEventListener) { //IE9, other browsers 
      a.addEventListener('click', clickLink2); // Attach event function 
     } else if (a.attachEvent) { //IE6,7,8, etc. 
      a.attachEvent('onclick', clickLink2); // Legacy IE Attach event function 
     }   

     a.onclick = function() { return false }; // override default onclick behavior for these anchors so URL is not followed 
    } 
} 

window.onload = init; //Attach event function 

function clickLink2() { 

    if(typeof(event) != 'undefined') { 
     elem = event.srcElement; //IE < 8 keeps this as window object 
    } else { 
     elem = this;  
    } 

    alert(elem.name); 
} 


function clickLink(elem) { 
    alert(elem.name); 
} 
</script> 

</head> 

<body> 

<!-- inline --> 
<a href="#" name="blah1" onclick="clickLink(this); return false;">Test 1</a> 
<a href="#" name="blah2" onclick="clickLink(this); return false;">Test 2</a> 
<a href="#" name="blah3" onclick="clickLink(this); return false;">Test 3</a> 
<a href="#" name="blah4" onclick="clickLink(this); return false;">Test 4</a> 


<hr/> 
<!-- not inline --> 
<a href="#" name="blah5" class="clickLink">Test 5</a> 
<a href="#?t" name="blah6" class="clickLink">Test 6</a> 
<a href="#" name="blah7" class="clickLink">Test 7</a> 
<a href="#" name="blah8" class="clickLink">Test 8</a> 

</body> 

</html> 
+4

聽起來像你需要閱讀關於['this'](https://developer.mozilla.org/en/JavaScript/Reference/Operators/this) – zzzzBov 2012-03-15 13:54:11

+1

你正在傳遞一個引用到當前元素'onclick =「點擊鏈接(this)'並在函數clickLink(elem)中接收它爲'elem'。爲什麼不使用那個? – Stefan 2012-03-15 13:56:21

+1

@Stefan我提供的代碼並不是真的想要做任何具體的事情,只是爲了弄清楚結合zzzzBov的MDN鏈接,下面的解釋以及我自己的修補程序,我認爲我現在可以更好地處理Javascript中的_this_了。謝謝所有 – user17753 2012-03-15 14:16:12

回答

2

1)clickLink爲什麼會出現這種指窗口對象? 簡單地說:clickLink不是事件處理程序,通過向元素添加屬性onclick,您使用本地onclick方法作爲調用函數的處理程序。這個函數是在主範圍內聲明的,因此它指向了窗口對象。 要明確:行爲與此類似:

<p onclick='function(){window.clickLink(this);}'> 

使實際的事件處理程序的匿名函數,而不是clickLink。這就是爲什麼它會指向window:annonymous函數也是在全局範圍內聲明的,因此clickLink的調用者是window。

2)爲什麼在clickLink2打印控制檯作爲鏈接的href值?

想一下這個短語'Javascript允許你操縱DOM,DOM樹,所有事件和行爲'。在你的init函數中,元素的onclick行爲被操縱。 onclick的默認方法正在被否決,並由此處的clickLink2方法nodeArr[i].onclick = clickLink2;取代。

看起來像這樣:你所有的元素都有一個原型onclick方法,它接受一個參數。在第一種情況下,該參數是一個字符串,該字符串計算對clickLink函數的調用。然而,第二種情況是,具有特定類的實例擁有自己的onclick方法,否定原型的onclick。

我確實希望這能爲您解決一些問題。一旦掌握事件,處理程序,方法,原型等的基本原理,並且克服JS的怪癖,這很容易。

3)有沒有更好的方式將此傳遞給像這樣的不顯眼的附件?你怎麼能確定這是指什麼?

那麼,上面的答案,不是嗎?但無論如何:如果你自己定義一個元素或對象的方法,一般來說,這將指向所有者對象/元素。如果你依賴html和默認行爲,JS會主要介意它自己的業務,這將指向窗口。

我不知道這是一種選擇,但也許你可以嘗試這樣的事:

<a onclick='clickLink'> 

這應該-in理論 - 做同樣的事情,你的初始化函數

編輯:工作替代上述:

<p onclick='clickLink.call(this)'> 

調用將定義p元素作爲clickLink的調用方,使此點指向調用該函數的元素。

2

當內嵌調用事件處理程序,他們在全球範圍內運行。這就是爲什麼thiswindow

當事件處理程序實際上附加到元素上時,它們將在該元素的上下文中調用,就像運行屬於對象一部分的方法一樣。這使得this的元素。

例如:

function test(){ 
    console.log(this); 
} 
test(); // window 

var obj = { 
    test: test 
} 
obj.test(); // obj 

可以肯定的是什麼this是,你應該重視使用JS的事件處理程序(與element.addEventListenerelement.onClick),而不是使用內聯處理程序。

+1

正確的,在我探索的示例代碼中內聯和動態連接的事件處理程序,我試圖確定兩個方法之間_this_的區別,看起來如果我通過'addEventLi stener'在附加函數體內的_this_將引用引發該事件的調用者。 – user17753 2012-03-15 14:25:21

2

這是我從.NET背景學到的關於JavaScript的最令人驚奇的事情之一。

this在方法中使用時並不涉及特定的對象。它指的是調用者,或引發事件的對象,導致調用事件處理程序。

爲了回答您的問題數3:只要複製任何這關係到一個新的變量:

var thisThis = this; 
//now pass thisThis. Interesting huh? 
//thisThis will not change with the change of the context. 
//this alone is a keyword that changes depending on 
//the context: e.g. who is the caller, what object raised the object, etc. 
+0

我想說的是#3,是內聯你可以傳遞_this_作爲第一個參數沒有問題,比如'click'中的'elem'。內聯'a'中的_this_指的是元素本身,並存儲在參數'elem'中。然而,當我通過'addEventListener'動態地附加一個函數時,我無法按照內聯的方式傳遞_this_。我猜這不是一個問題,因爲附加函數體內的_this_指的是調用者。 – user17753 2012-03-15 14:20:56

+0

此外,我想知道,#2:是否只是當'a'標籤打印到控制檯'toStrings'到它的'href'的值時? – user17753 2012-03-15 14:22:25

2

this是一個變量指向當前範圍。如果您在控制檯中執行以下代碼:

var myPackage = {} 
myPackage.method = function() {console.log(this)} 
myPackage.method() 

this將指向myPackage對象(的method範圍內)。

相反,如果你嘗試運行如下:

console.log(this) // window 

這(窗口)是參考當前瀏覽器窗口中的腳本執行

+0

「範圍」在JavaScript中的含義略有不同。這可能不是最好的詞,因爲它是不明確的。 – pimvdb 2012-03-15 14:02:04