2012-03-15 81 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