後輩から、以下のコードが動かないのがわからないという相談を受けた。(一部改変)
<!DOCTYPE html>
<title>ugougo</title>
<form>
<input type="button" value="送信" onclick="submit()">
</form>
<script>
function submit() {
alert(1);
}
</script>
まさかと思ってやってみたが本当に動かない。submit()
を呼ぶとthis.form.submit()
が呼ばれて本当にsubmitされてしまう。謎だ。
半時間ほど調べてみたところ、以下の仕様が見つかった。
Lexical Environment Scope
- Let Scope be the result of NewObjectEnvironment(document, the global environment).
- If form owner is not null, let Scope be the result of NewObjectEnvironment(>form owner, Scope).
- If element is not null, let Scope be the result of NewObjectEnvironment(element, Scope).
http://www.w3.org/TR/html5/webappapis.html#getting-the-current-value-of-the-event-handler
要するに、上のsubmit()
は、機能的に以下のコードとほぼ等価である。
with (this.form) {
with (this) {
submit();
}
}
つまり、onclickからid
を参照するとthis.id
が呼ばれ、submit
を参照するとthis.form.submit
が呼ばれるのだ。キモいことこの上ないが、仕様なのでしかたがない。もともと<script>
にはtypeが指定できるのにイベント属性にはtypeが指定できないというエモい仕様だけど