2009-09-12 15 views
7

実行していないjavascript関数があり、エラーがスローされました。私のフォームが関数と同じ名前を持っていたことに気づくのに約1時間かかりました。フォーム名が関数名と矛盾していることは奇妙に思えましたが、とにかく名前を変更してもすべて正常に機能しました。誰もがなぜこれが起こるのか知っていますか?Javascript関数とフォーム名の競合

このコードを実行すると失敗しますが、フォーム名を変更すると非常に奇妙です。

<html> 
<head> 
<title>Untitled Document</title> 
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 
<script type="text/javascript"> 
function mytest(){alert("hello");} 
</script> 
</head> 
<body> 
<form name="mytest" ></form> 
<a href="#" onClick="mytest();">Click Me</a> 
</body> 
</html> 

私はIE6でこれを実行しています。私にとって奇妙なのは、1つがJavascriptコードで、もう1つがHTMLの属性であるということです。

あなたはこの出来事を見ることができますライブリンク:
JSBin

+0

私はこのリンクもhttp://oreilly.com/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html –

答えて

6

機能がwindowオブジェクト内のメンバーであり、そしてフォームがdocumentオブジェクト内のformsコレクションのメンバーです。スクリプトが識別子 "mytest"の一致を検索すると、最初にdocumentオブジェクトが検索され、そこに見つからない場合はwindowオブジェクトが検索されます。

あなたはそれがwindowオブジェクト内だと指定した場合、あなたも矛盾フォーム名と機能にアクセスすることができます:あなたはjavascriptののスコープチェーンを理解する必要があり、ここで何が起こっているのかにいくつかの詳細を追加するには

<a href="#" onClick="window.mytest();">Click Me</a> 
+2

について説明しましたが、ブラウザによっても異なります。 IEは、IDまたはNAME属性を宣言するページ上のすべての要素のメンバーでグローバル名前空間を汚染します。言うまでもなく、多くの問題を引き起こします。それはほとんどの場合IEをサポートする必要があるため、関数名がページの要素の名前/ ID値と衝突しないようにすることをお勧めします。 – scunliffe

+0

@Scunliffe:実際この場合、他のブラウザが影響を受けます。また、IEがjavascriptで定義された名前に優先順位を与えることにも注意してください。スコープ内の名前に対する標準のjavascript検索が何も表示されない場合に限り、IEはあなたの提案する方法で名前を解決しようとします。したがって、この例のテストケースは失敗しませんでした。 – AnthonyWJones

7

スコープオブジェクト

スコープオブジェクトは、任意の機能実行内側function名前プロパティは、また、上のプロパティとして配置されているようにvarで宣言された変数が配置されている機能が実行されたときに作成さ隠されたオブジェクトでありますスコープオブジェクト

mytestのような識別子が要求されると、javascriptは現在のスコープオブジェクト(スコープオブジェクトは「実行コンテキスト」とも呼ばれます)に添付されたその名前を検索します。関数は関数内で宣言された場合

スコープチェーン

現在のスコープオブジェクトが関数に取り付けられています。この内部関数が実行されている(したがって独自のスコープオブジェクトを持っている)場合、実行中のコードは現在のスコープオブジェクトだけでなく、現在実行中の関数が作成されたスコープオブジェクトにもアクセスできます。 ここで停止し、最後の文章をもう一度読んでください。これはスコープチェーンと呼ばれ、チェーンは関数内に関数があるほど深くなります(これはJQueryのようなフレームワークを使用すると多く発生します)。

したがって、現在のスコープオブジェクトで識別子の検索が失敗した場合、チェーンの次のスコープオブジェクトを調べます。グローバルオブジェクトにヒットするまでチェーンを歩いていきます(グローバルレベルで宣言された関数はグローバルオブジェクトをスコープオブジェクトとして持っています)。ブラウザは、このようなことが関数であるかのように、それは、このコードを扱いますonclickのよう属性のテキスト内のコードを実行すると

イベントはすごみ

属性。しかし、ブラウザは、この "関数"に付けられた見かけ上のスコープチェーンで奇妙なことをします。通常、スコープチェーン内のスコープオブジェクトであるかのように、現在の要素とドキュメント要素(およびその間の他の要素)を注入します。

たとえば、あなたの例のonclickコードを "alert(href)"に変更します。あなたのページへのパスの後に、警告ボックスに#が続きます。これは、現在の要素がスコープチェーン内にあり、したがってhrefがそのhrefプロパティによって解決されるためです。

質問の場合、コードはdocumentスコープチェーン(グローバルウィンドウオブジェクトの上に配置されています)に到着し、識別子 "mytest"(これはフォームへの参照です)を見つけて使用しようとしますその値を関数として返します(失敗する)。

+0

いい説明、アンソニー。私が変更する唯一のことは、 "スコープオブジェクト"を "変数オブジェクト"(これは実際には:)と呼ぶ名前に変更することです)。誤解を招くもう一つのことは、「名前付き関数」がVariableオブジェクトのメンバーであることです。ではない。関数宣言はありますが、関数式はそうではありませんが、 "名前"(iow、識別子を持っている)でもかまいません。最後に、本質的なイベントハンドラ本体のスコープに関心を持つ人は、この記事(http://www.jibbering.com/faq/names/event_handler.html)を読んでください。この記事では、件名に関する詳細を詳しく解説しています。 – kangax

+0

@ Kangax:あなたのコメントをありがとう。はい、厳密に言えば、ECMA 262は「変数オブジェクト」という用語を使用していますが、何らかの「オブジェクト」が何らかの形で「変化する」ことを意味するので、IMOは愚かな名前です。この言葉は、このことをコンピュータに説明する実装者にとっては間違いないが、人間間の理解のためにはごみを発生させるスペックの文脈においてのみ意味をなさない。 「スコープオブジェクト」という用語は単独で存在し、スコープに関連するオブジェクトがあることを意味し、スコープチェーンと呼ばれる他のオブジェクトに関連する可能性が高いという理由も簡単です。 – AnthonyWJones

+0

@ Kangax:「名前付き関数」に関する限り、私はあなたの推論に従うかどうかはわかりません。 Variableオブジェクトにその名前がなくても関数式に名前を付けることができますが、実際に何を意味しているのかは分かりません。 – AnthonyWJones