【问题标题】:onClick Function "this" Returns Window ObjectonClick 函数“this”返回窗口对象
【发布时间】:2012-09-11 05:36:19
【问题描述】:

我的 JavaScript 应用程序遇到了令人头疼的问题。

如果我这样写一个元素:

<li onClick="alert(this.tagName)"></li>

我得到“LI”。

但是,如果我这样做:

<li onClick="foo()"></li>

“foo()”在哪里:

function foo(){ alert(this.tagName); }

我得到“未定义”。

我不知道“this”在附加功能方面应该如何工作。但是,我很困惑,因为“this”没有提取元素,而是显然默认为“window”。我不知道为什么会这样。

有人解释一下吗?

【问题讨论】:

  • 请先尝试搜索。有很多重复。 this 被“动态绑定”到函数的 receiver 或全局对象(例如 window)。
  • 提示:&lt;li onClick="foo()"&gt;&lt;/li&gt; 将 foo() 包装在匿名函数中,而不是直接调用 foo()。
  • 提示2:this的含义,与你使用它的地方有关。
  • 如果您删除内联事件处理程序,您可能会发现它更明智。

标签: javascript function onclick window this


【解决方案1】:

这是因为您没有在 JavaScript 函数调用中传递对 this 的引用。 JavaScript 函数中的 this 引用的对象与 onClick 示例中的对象不同。试试这个:

 <li onClick="foo(this)"></li>

 function foo(item){ alert(item.tagName); }

【讨论】:

  • this 与作用域无关。
  • this 完全由函数的调用方式设置(忽略ES5 bind)。调用上下文(即建立范围的全局或函数上下文)是无关紧要的。如果调用未设置this,则无论在何处调用函数,它将默认为非严格模式下的全局对象,并且this可以在从任何上下文调用时设置为任何对象(即它有与范围无关)。
  • @RobG 啊,我明白了……感谢您的澄清和更正!我已经编辑了我的答案。
  • 为了增加可移植性,你也可以这样使用:
  • 被调用的函数将继承调用元素作为“this”。
【解决方案2】:

在内联监听器中:

> <li onClick="alert(this.tagName)"></li>

onclick 属性值被有效地包装在一个函数中,并使用设置为 this 的元素调用,例如

function anon() {
  /* attribute value */
}

anon.call(element);

当你将一个函数放入主体中时,你实际上得到了:

function anon() {
  foo();
}

这里,anon 内的this 将是元素,但由于在未设置this 的情况下调用foo,因此它将未定义。在非严格模式下,this 将默认为全局对象(浏览器中的window)。在严格模式下,this 内的foo 将是未定义的。

一种解决方案是将元素引用传递给函数:

<li onclick="foo(this)" ... >

然后在函数中:

function foo(callingElement) {
  ...
}

甚至:

<li onclick="foo.call(this)" ... >

function foo() {
  var callingElement = this;
}

【讨论】:

    【解决方案3】:

    正如其他答案已经提到的那样,this 的值将取决于包含它的函数的调用方式。但是由于您的示例是关于事件处理程序的,所以我想强调一下 cjc343 在 cmets 上所说的内容:

    如果您删除内联事件处理程序,您可能会发现它更明智。

    其实很简单。考虑到这个 HTML:

    <ul id="list">
        <li id="item1">item 1</li>
        <li id="item2">item 2</li>
        <li id="item3">item 3</li>
    </ul>
    

    以下 JavaScript 将说明删除内联处理程序和使用委托:

    var list = document.getElementById('list');
    list.addEventListener('click', function(evt){
        console.log("this is the element the event is bound to: " + this.id);
        console.log("the event target is the clicked element: " + evt.target.id);
    });
    

    http://jsfiddle.net/J3Gje/

    这将适用于所有符合 W3C 事件模型的浏览器,包括 IE9。对于较旧的 IE,您必须使用 attachEvent 而不是 addEventListener,并在事件名称前加上 "on"。更多详情here.

    【讨论】:

      【解决方案4】:

      另一个选项是使用call 或apply,这样您就不必将this 作为参数传递。这是一种在函数中设置 this 值的内置机制。尽管我要指出,将事件处理程序直接添加到 html 有点过时。您可能想查看事件委托的 JS 框架(jQuery、Prototype、Dojo、YUI 等)。

      小提琴:http://jsfiddle.net/bboone/Q2CkV/2/

      HTML

      <div onClick='alert(this.tagName);'>test</div>
      <div onClick='foo.call(this);'>test2</div>​
      

      JS

      function foo(){ alert(this.tagName); }
      

      【讨论】:

        【解决方案5】:

        如果您是 JavaScript 新手,请不要使用 this 或 new 关键字,因为您可能会弄错,或者您的代码会不必要地低效和复杂。但是,您要完成的工作如下:

        <li onclick="foo(this)">some text</li>
        

        在该示例中,该列表项的单击事件会触发名为 foo 的函数。 this 关键字作为变量传入。 this 关键字仅指调用相关函数的实体,如果找不到该实体,它将引用浏览器的window 对象。在这种情况下,调用该函数的实体是 DOM 中的列表项节点。

        我仍然建议永远不要使用 this 关键字,以避免这种混淆。

        编辑:另外,不要使用 tagName 属性,因为这不是标准的。而是使用 nodeName 属性。

        【讨论】:

        • Element.tagName 由 DOM 级别 2 提供,就像 Node.nodeName 一样。您避免使用 this 和 new 的建议令人不安 - 如果您学会使用它们,它们就不会令人困惑。
        • @Dennis 我不同意。我从未见过比不使用该关键字的类似逻辑更清晰或更简单的this 用法。因此,我看到许多来自其他语言的人试图使用this 创建类结构以使 JavaScript 适应他们以前的经验,这是不合理的。 this 也是 JavaScript 的代名词,代词不服务于编程的利益。我非常乐意接受反对票,因为我将继续坚持我的意见。
        猜你喜欢
        相关资源
        最近更新 更多
        热门标签