web-dev-qa-db-ja.com

onClick関数「this」はWindowオブジェクトを返します

JavaScriptアプリケーションで頭を悩ませる問題に遭遇しました。

このような要素を書くと:

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

「LI」が表示されます。

ただし、これを行うと:

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

「foo()」は次のとおりです。

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

「未定義」になります。

アタッチされた関数に関して「これ」がどのように機能することになっているのか私は離れています。しかし、「これ」は要素を拾っていないため、デフォルトでは「ウィンドウ」にデフォルト設定されているため、困惑しています。なぜこれが起こっているのか理解できません。

誰か説明がありますか?

15
Pori

これは、JavaScript関数呼び出しでthisへの参照を渡していないためです。 JavaScript関数のthisonClickの例と同じオブジェクトを参照しません。代わりにこれを試してください:

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

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

インラインリスナーで:

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

Onclick属性値は効果的に関数にラップされ、これに設定された要素で呼び出されます。

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

anon.call(element);

本体に関数を置くと、基本的に次のようになります。

function anon() {
  foo();
}

ここでは、this内のanonが要素になりますが、foothisを設定せずに呼び出されるため、未定義になります。非厳密モードでは、thisはデフォルトでグローバルオブジェクト(ブラウザではwindow)になります。厳密モードでは、this内のfooは未定義になります。

1つの解決策は、要素参照を関数に渡すことです。

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

次に関数で:

function foo(callingElement) {
  ...
}

あるいは:

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

function foo() {
  var callingElement = this;
}
3
RobG

他の回答ですでに述べたように、thisの値は、それを含む関数の呼び出し方法によって異なります。しかし、あなたの例はイベントハンドラーに関するものなので、コメントでcjc343が言ったことを強調したいと思います。

インラインイベントハンドラーを削除すると、よりわかりやすくなる場合があります。

実際、それは非常に簡単です。この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/

これは、IE9を含むW3Cイベントモデルに準拠するすべてのブラウザーで機能します。古いIEでは、attachEventの代わりにaddEventListenerを使用し、イベント名の前に"on"を追加する必要があります。詳細 こちら

2
bfavaretto

thisをパラメーターとして渡す必要がない別のオプションは、 call または 適用 。これは、関数内でthisの値を設定するための組み込みメカニズムです。指摘しておきますが、HTMLに直接イベントハンドラーを追加するのは少し時代遅れです。イベントの委任についてJSフレームワークをチェックアウトすることをお勧めします( jQueryPrototypeDojo[〜#〜] 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); }
0
Brandon Boone