回答:
どちらも正しいですが、どちらもそれ自体が「最良」ではなく、開発者が両方のアプローチを選択した理由がある可能性があります。
イベントリスナー(addEventListenerおよびIEのattachEvent)
以前のバージョンのInternet Explorerは、他のほとんどのブラウザとは異なる方法でJavaScriptを実装しています。9未満のバージョンでは、次のようにattachEvent
[ doc ]メソッドを使用します。
element.attachEvent('onclick', function() { /* do stuff here*/ });
他のほとんどのブラウザー(IE 9以降を含む)では、次のようにaddEventListener
[ doc ] を使用します。
element.addEventListener('click', function() { /* do stuff here*/ }, false);
このアプローチ(DOMレベル2のイベント)を使用すると、理論的には無制限の数のイベントを任意の1つの要素にアタッチできます。唯一の実用的な制限は、クライアント側のメモリとその他のパフォーマンスの問題であり、ブラウザーごとに異なります。
上記の例は、無名関数[ doc ]の使用を表しています。関数reference [ doc ]またはクロージャ[ doc ] を使用してイベントリスナーを追加することもできます。
var myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
のもう1つの重要な機能はaddEventListener
、リスナーがバブリングイベントにどのように反応するかを制御するfinalパラメータです[ docです ]。例ではfalseを渡していますが、これはおそらく95%のユースケースで標準です。attachEvent
、またはインラインイベントを使用する場合、同等の引数はありません。
インラインイベント(HTML onclick = ""プロパティおよびelement.onclick)
JavaScriptをサポートするすべてのブラウザで、イベントリスナをインラインに配置できます。つまり、HTMLコード内に直接挿入できます。あなたはおそらくこれを見たでしょう:
<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
ほとんどの経験豊富な開発者はこの方法を回避しますが、それは仕事を成し遂げます。シンプルで直接的です。ここでは、クロージャーや匿名関数を使用できません(ただし、ハンドラー自体は一種の匿名関数です)。スコープの制御は制限されています。
あなたが言及する他の方法:
element.onclick = function () { /*do stuff here */ };
...はインラインJavaScriptと同等ですが、スコープをより詳細に制御でき(HTMLではなくスクリプトを記述しているため)、匿名関数、関数参照、クロージャーを使用できます。
インラインイベントの大きな欠点は、上記のイベントリスナーとは異なり、1つのインラインイベントしか割り当てられない可能性があることです。インラインイベントはelement [ doc ]の属性/プロパティとして保存されます。つまり、上書きできます。
<a>
上記のHTML の例を使用します。
var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
...要素をクリックすると、「Did stuff#2」のみが表示されます。最初に割り当てられたonclick
プロパティと2番目の値が上書きされ、元のインラインHTML onclick
プロパティも上書きされました。こちらで確認してください:http : //jsfiddle.net/jpgah/。
大まかに言って、インラインイベントは使用しないでください。特定のユースケースがあるかもしれませんが、そのユースケースが100%確実でない場合は、インラインイベントを使用しないでください。
最新のJavascript(Angularなど)
この回答はもともと投稿されていたため、AngularなどのJavaScriptフレームワークははるかに人気が高まっています。Angularテンプレートに次のようなコードが表示されます。
<button (click)="doSomething()">Do Something</button>
これはインラインイベントのように見えますが、そうではありません。このタイプのテンプレートは、背後でイベントリスナーを使用するより複雑なコードに変換されます。ここで私がイベントについて書いたことはすべて当てはまりますが、あなたは少なくとも1つのレイヤーによって要塞から取り除かれます。本質を理解する必要がありますが、最新のJSフレームワークのベストプラクティスでこの種のコードをテンプレートに記述する必要がある場合は、インラインイベントを使用しているように感じないでください-そうではありません。
どちらがベストですか?
問題は、ブラウザの互換性と必要性の問題です。要素に複数のイベントをアタッチする必要がありますか?あなたは将来的にですか?オッズは、あなたがします。attachEventおよびaddEventListenerが必要です。そうでない場合、インラインイベントはそれらがうまくいくように見えるかもしれませんが、それは、ありそうにないように見えるかもしれませんが、少なくとも予測可能である未来への準備にはるかによく役立ちます。JSベースのイベントリスナーに移動する必要がある可能性があるため、そこから開始することもできます。インラインイベントは使用しないでください。
jQueryおよびその他のJavaScriptフレームワークは、DOMレベル2イベントのさまざまなブラウザー実装を汎用モデルにカプセル化するため、IEの歴史を反逆者として心配する必要なく、クロスブラウザー準拠のコードを記述できます。jQueryを使用した同じコード、すべてのクロスブラウザーですぐに使える:
$(element).on('click', function () { /* do stuff */ });
ただし、不足しないで、このためのフレームワークを取得しないでください。独自の小さなユーティリティを簡単にロールして、古いブラウザを処理できます。
function addEvent(element, evnt, funct){
if (element.attachEvent)
return element.attachEvent('on'+evnt, funct);
else
return element.addEventListener(evnt, funct, false);
}
// example
addEvent(
document.getElementById('myElement'),
'click',
function () { alert('hi!'); }
);
試してみてください:http : //jsfiddle.net/bmArj/
これらすべてを考慮に入れて、あなたが見ているスクリプトがブラウザーの違いを他の方法で考慮しない限り(質問に示されていないコードで)、使用addEventListener
する部分は9より前のIEバージョンでは機能しません。
ドキュメントと関連資料
function addEvent(e,n,f){return e.attachEvent?e.attachEvent('on'+n,f):e.addEventListener(n,f,!!0)}
<< 98文字では、これは40%以上小さくなります!
他にいくつかの機能があるかどうかで、違いがわかります。
var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;
h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);
関数2、3、4は機能しますが、1は機能しません。これは、addEventListener
イベントハンドラを既存の上書きされていないのに対し、onclick
上書き任意のは、既存のonclick = fn
のイベントハンドラ。
もちろん、その他の重要な違いは、onclick
常に機能addEventListener
することですが、バージョン9より前のInternet Explorerでは機能しません。IE<9 attachEvent
では、類似の(構文がわずかに異なる)を使用できます。
この回答では、DOMイベントハンドラーを定義する3つの方法について説明します。
element.addEventListener()
コード例:
element.addEventListener()
複数の利点があります:
element.removeEventListener()
。useCapture
あなたは、その中でイベントを処理したいかどうかを示すパラメータ、キャプチャまたはバブリング段階を。参照:addEventListenerのuseCapture属性を理解できません。.onevent
、DOM要素のプロパティにイベントリスナーを割り当てるため、経験の浅いJavaScriptプログラマーの多くは、イベント名がonclick
やなどであると考えていonload
ます。on
はイベント名の一部ではありません。正しいイベント名はclick
and load
であり、それがイベント名がに渡される方法.addEventListener()
です。element.onevent = function() {}
(例えばonclick
、onload
)コード例:
これは、DOM 0でイベントハンドラーを登録する方法でした。次の理由により、現在は推奨されていません。
onevent
プロパティを初期状態(つまりnull
)に戻す必要があるためです。window.onload
に割り当てた場合(例window.onload = "test";
:)、エラーはスローされません。あなたのコードは機能せず、その理由を見つけるのは本当に難しいでしょう。.addEventListener()
ただし、エラーをスローします(少なくともFirefoxでは):TypeError:EventTarget.addEventListenerの引数2はオブジェクトではありません。onevent
HTML属性)コード例:
と同様にelement.onevent
、現在は推奨されていません。ある問題に加えelement.onevent
て、それは:
Content-Security-Policy
HTTPヘッダーを送信してインラインスクリプトをブロックし、信頼できるドメインからの外部スクリプトのみを許可する必要があります。参照コンテンツセキュリティポリシーのしくみを教えてください。addEventListener
複数のイベントを追加できますが、これをonclick
行うことはできません。onclick
HTML
属性として追加できますが、addEventListener
は<script>
要素内でのみ追加できます。addEventListener
イベントの伝播を停止できる3番目の引数を取ることができます。どちらもイベントの処理に使用できます。ただし、addEventListener
すべてのことを実行できるため、推奨される選択肢onclick
です。onclick
これはJavaScriptとHTMLを混同するため、HTML属性としてインラインを使用しないでください。これは悪い習慣です。コードの保守性が低下します。
onclick
つまり、部屋から笑われるのを恐れて、個人的にインラインハンドラーを使用するつもりはありません。のようなクラスjs-link
、js-form-validation
またはを使用したデータ属性data-jspackage="init"
は、決して優れたものではありません...そして、実際にイベントバブリングをどの程度使用していますか?個人的には、ターゲットが実際に私の要素と一致するかどうかを確認せずにハンドラーを記述できるようにしたいと思います。あるいは、ランダムなバグのためにいくつかの場所で伝播を停止する必要があります。
1つの詳細はまだ認められていません:最新のデスクトップブラウザは異なるボタンの押下がために「クリック」であることを考えるAddEventListener('click'
とonclick
、デフォルトで。
onclick
、AddEventListener
左クリックと中クリックで発砲します。onclick
火災だけ左クリックではなくAddEventListener
、左ミドルで火災をクリックし、右クリック。また、スクロールカーソルが関係している場合、ブラウザ間でミドルクリックの動作に一貫性がありません。
また、キーボードで選択可能なHTML要素の「クリック」イベントはinput
、要素が選択されたときにスペースで発生したり、Enterしたりすることにも注意してください。
JavaScriptはすべてをオブジェクトにブレンドする傾向があり、混乱を招く可能性があります。1つにすべてがJavaScriptの方法です。
基本的に、onclickはHTML属性です。逆に、addEventListenerは、HTML要素を表すDOMオブジェクトのメソッドです。
JavaScriptオブジェクトでは、メソッドは、値として関数を持ち、アタッチされているオブジェクト(たとえば、これを使用)に対して機能するプロパティにすぎません。
JavaScriptでは、DOMで表されるHTML要素として、属性がそのプロパティにマッピングされます。
JavaScriptはすべてを単一のコンテナーまたは名前空間に統合し、間接参照のレイヤーがないため、人々は混乱します。
通常のOOレイアウト(少なくともプロパティ/メソッドの名前空間をマージする)では、次のようになります。
domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))
onloadにはゲッター/セッターを、属性にはHashMapを使用できるようなバリエーションがありますが、最終的にはそのようになります。JavaScriptは、とりわけ何が何であるかを知ることを期待して、間接層を取り除きました。domElementと属性をマージしました。
互換性がない場合は、ベストプラクティスとしてaddEventListenerを使用する必要があります。他の回答が、プログラムに関する基本的な違いではなく、その点での違いについて話しているので、私はそれを忘れます。基本的に、理想的な世界では、HTMLからon *を使用することだけが意図されていますが、さらに理想的な世界では、HTMLからそれを行うべきではありません。
今日はなぜそれが支配的ですか?書くのが速く、習得が簡単で、うまく機能する傾向があります。
HTMLのonloadの要点は、そもそもaddEventListenerメソッドまたは機能へのアクセスを提供することです。JSで使用することで、HTMLを直接適用できる場合にHTMLを使用できます。
仮説的には、独自の属性を作成できます。
$('[myclick]').each(function(i, v) {
v.addEventListener('click', function() {
eval(v.myclick); // eval($(v).attr('myclick'));
});
});
JSが行うことは少し異なります。
あなたはそれを(作成されたすべての要素について)のようなものと同等にすることができます:
element.addEventListener('click', function() {
switch(typeof element.onclick) {
case 'string':eval(element.onclick);break;
case 'function':element.onclick();break;
}
});
実際の実装の詳細は、さまざまな微妙なバリエーションによって異なる可能性が高く、場合によっては2つがわずかに異なりますが、それがその要点です。
デフォルトでは属性はすべて文字列であるため、関数をon属性に固定できるのは間違いなく互換性のハックです。
MDNによると、違いは次のとおりです。
addEventListener:
EventTarget.addEventListener()メソッドは、指定されたEventListener互換オブジェクトを、それが呼び出されたEventTargetの指定されたイベントタイプのイベントリスナーのリストに追加します。イベントターゲットは、ドキュメント内の要素、ドキュメント自体、ウィンドウ、またはイベントをサポートするその他のオブジェクト(XMLHttpRequestなど)です。
onclick:
onclickプロパティは、現在の要素のクリックイベントハンドラーコードを返します。クリックイベントを使用してアクションをトリガーする場合は、これと同じアクションをkeydownイベントに追加して、マウスやタッチスクリーンを使用しないユーザーが同じアクションを使用できるようにすることも検討してください。構文element.onclick = functionRef; ここで、functionRefは関数です。多くの場合、他の場所で宣言された関数の名前または関数式です。詳細については、「JavaScriptガイド:関数」を参照してください。
以下のコードに見られるように、使用には構文の違いもあります:
addEventListener:
// Function to change the content of t2
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
onclick:
function initElement() {
var p = document.getElementById("foo");
// NOTE: showAlert(); or showAlert(param); will NOT work here.
// Must be a reference to a function name, not a function call.
p.onclick = showAlert;
};
function showAlert(event) {
alert("onclick Event detected!");
}
ブラウザのサポートについてあまり心配していない場合は、イベントによって呼び出される関数で「this」参照を再バインドする方法があります。これは通常、関数が実行されたときにイベントを生成した要素を指しますが、これは必ずしも必要なことではありません。トリッキーな部分は、次の例に示すように、非常に同じイベントリスナーを同時に削除できることです:http : //jsfiddle.net/roenbaeck/vBYu3/
/*
Testing that the function returned from bind is rereferenceable,
such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
// the following is necessary as calling bind again does
// not return the same function, so instead we replace the
// original function with the one bound to this instance
this.swap = this.swap.bind(this);
this.element = document.createElement('div');
this.element.addEventListener('click', this.swap, false);
document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
element: null,
swap: function() {
// now this function can be properly removed
this.element.removeEventListener('click', this.swap, false);
}
}
上記のコードはChromeで適切に動作し、おそらく「バインド」を他のブラウザと互換にすることについていくつかのシムがあるでしょう。
インラインハンドラを使用することと互換性がありませんコンテンツセキュリティポリシーようaddEventListener
なアプローチは、その観点から、より安全です。もちろん、インラインハンドラーを有効にすることもできますunsafe-inline
が、その名前が示すように、CSPが防止するJavaScriptエクスプロイトの大群全体を取り戻すのは安全ではありません。
プロトタイピングによってリスナーを拡張することもできます(参照があり、無名関数ではない場合)-または、 'onclick'呼び出しを関数ライブラリ(他の関数を呼び出す関数)に呼び出します
お気に入り
elm.onclick = myFunctionList
function myFunctionList(){
myFunc1();
myFunc2();
}
これは、onclick呼び出しを変更する必要がないことを意味します。関数myFunctionList()を変更して必要な処理を実行するだけですが、これによりバブリング/キャッチフェーズを制御できなくなるため、新しいブラウザーでは回避する必要があります。
誰かが将来このスレッドを見つけた場合に備えて...
element.onclick = function(){/ *何かを行う* /}
element.addEventListener( 'click'、function(){/ * do stuff * /}、false);
それらは明らかに同じことを行います。クリックイベントをリッスンし、コールバック関数を実行します。それにもかかわらず、それらは同等ではありません。2つのうちどちらかを選択する必要がある場合、これはどちらが最適かを判断するのに役立ちます。
主な違いは、onclickは単なるプロパティであり、すべてのオブジェクトプロパティと同様に、複数回書き込むと上書きされます。addEventListener()の代わりに、我々は単にすることができ、イベントハンドラをバインド要素に、そして我々はすべての上書きされたプロパティを心配することなく、それを必要とするたびにそれを呼び出すことができます。ここに例を示します。
試してみてください:https : //jsfiddle.net/fjets5z4/5/
そもそもonclickを使い続けたくなったのは、それが短くてシンプルに見えるからです…実際はそうです。しかし、私はそれをもう使うことを勧めません。インラインJavaScriptを使用するのと同じです。今日ではインラインJavaScriptのようなものを使用することは非常に推奨されていません(インラインCSSも推奨されていませんが、それは別のトピックです)。
ただし、addEventListener()関数は標準ですが、古いブラウザー(バージョン9より前のInternet Explorer)では機能しません。これは、もう1つの大きな違いです。これらの古いブラウザをサポートする必要がある場合は、onclickの方法に従う必要があります。ただし、jQuery(またはその代替手段の1つ)を使用することもできます。これにより、基本的に作業が簡略化され、ブラウザー間の差異が減少するため、時間を大幅に節約できます。
var clickEvent = document.getElementByID("onclick-eg");
var EventListener = document.getElementByID("addEventListener-eg");
clickEvent.onclick = function(){
window.alert("1 is not called")
}
clickEvent.onclick = function(){
window.alert("2 is not called")
}
EventListener.addEventListener("click",function(){
window.alert("1 is called")
})
EventListener.addEventListener("click",function(){
window.alert("2 is also called")
})
addEventListener
複数のハンドラを設定できますが、IE8以前ではサポートされていません。
IEにはありますがattachEvent
、完全に同じではありません。
'this'
JavasSriptのキーワードによって参照されるコンテキストが異なります。
次のコードを見てください。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<input id="btnSubmit" type="button" value="Submit" />
<script>
function disable() {
this.disabled = true;
}
var btnSubmit = document.getElementById('btnSubmit');
btnSubmit.onclick = disable();
//btnSubmit.addEventListener('click', disable, false);
</script>
</body>
</html>
それがすることは本当に簡単です。ボタンをクリックすると、ボタンは自動的に無効になります。
最初にこの方法でイベントをフックしようとbutton.onclick = function(),
すると、ボタンをクリックしてonclickイベントがトリガーされますが、button.onclickとonclickイベントハンドラーの間に明示的なバインディングがないため、ボタンは無効になりません。デバッグして'this'
オブジェクトを表示すると、'window'
オブジェクトを参照していることがわかります。
次に、コメントを付けbtnSubmit.onclick = disable();
たりコメント//btnSubmit.addEventListener('click', disable, false);
を外したり
すると、ボタンが無効になっていることがわかります。この方法では、button.onclickイベントとonclickイベントハンドラーの間に明示的なバインディングがあるためです。無効化機能にデバッグする場合、参照で'this'
はbutton control
なく参照を参照できますwindow
。
これは、一貫性のないJavaScriptについて私が気に入らない点です。ところで、jQuery($('#btnSubmit').on('click', disable);
)を使用している場合は、明示的なバインディングを使用します。
btnSubmit.onclick = disable;
(それを呼び出すのではなく、関数を割り当ててください)。次に、どちらの場合もthis
ボタン要素を参照します。
onclickは基本的に、要素がクリックされたときに特定の機能を実行するaddEventListenerです。そのため、電卓のボタンなど、簡単な操作を行うボタンがある場合に便利です。addEventlistenerは、DOMまたはすべてのコンテンツがロードされたときに操作を実行するなど、window.onloadに似ていますがより詳細に制御できるなど、さまざまな目的に使用できます。
注:インラインで複数のイベントを実際に使用することも、少なくともonclickを使用して各関数をセミコロンで区切ることにより、このようにできます。
後で問題が発生する可能性があり、面倒なimoになるため、インラインで関数を記述しません。スクリプトファイルで既に実行されている関数を呼び出すために使用します。
どちらを使用するかは、あなたが望むものに依存すると思います。複雑な操作にはaddEventListener、単純な操作にはonclick。特定の要素を要素にアタッチしないプロジェクトがいくつかあり、代わりに、ボタンがタップされたかどうかを判断し、何が押されたかに応じて特定のタスクを実行する、よりグローバルなイベントリスナーを実装します。考えられる問題につながる可能性のあるImoであり、イベントリスナーがすべてのクリックを処理する必要がある場合、リソースの無駄になる可能性があります。
function addEvent(element, myEvent, fnc) { return ((element.attachEvent) ? element.attachEvent('on' + myEvent, fnc) : element.addEventListener(myEvent, fnc, false)); }