25

次のコード ブロックを実行すると、typeof(hiya) = stringIE7/8 の出力中に FF と Chrome が出力されますtypeof(hiya) = undefined

<html>
    <body>
        <script type="text/javascript">
            window.hiya = 'hiya';
        </script>
        <script type="text/javascript">
            if( false ) {
                var hiya = 1;
            }
            document.write( "typeof(hiya) = "+ typeof(hiya) );
        </script>
    </body>
</html>

次のそれぞれが問題を解消します。

  • すべてを 1 つの<script>ブロックにまとめます。
  • ifブロックの取り外し。
  • var hiya = 1に改名var hiya2 = 1
  • var hiya = 1に改名window.hiya = 1
  • var hiya = 1に改名hiya = 1

何が起こっている?IE にスコーピング バグはありますか?

4

3 に答える 3

27

IE はばかげており、それを認識せず、場合によっては同じ変数にアクセスしますwindow.varNamevar varName

新しいスクリプト タグが検出されると、最初に var で宣言されたすべての変数が初期化されます。var ステートメント ("hiya" に初期化する部分) は実行しません。未定義に初期化するだけです。ただし、以前に var で宣言されていた場合はそうしません。

コードが単一のスクリプト タグ内にある場合、このエラーは発生しません。また、hiya の最初の宣言が var で行われた場合、このエラーも発生しませんでした。

具体的には、2 番目のスクリプト タグで、IE は最初に var ステートメントを探し、var を見つけvar hiya = 1ます。次に、 hiya は以前に var ステートメントで初期化されていないことを示し (IE は愚かで、他のブラウザーは window.hiya が同じことを行うことを認識します)、コードを実行する前に、window.hiya を上書きして hiya を初期化します。

可能な解決策:

  • コードを同じスクリプト タグ内に保持する
  • window.hiYa で変数を初期化しないでください
  • スクリプトのいずれかを制御しない場合は、var を使用するスクリプトが最初に来るようにしてください。

JS パーサーがコードに対して行うことを明確にするための最後のメモ。JS パーサーがコードを確認すると、次のように変換します。

<html>
    <body>
        <script type="text/javascript">
            window.hiya = 'hiya';
        </script>
        <script type="text/javascript">
            // IE is dumb, it doesn't recognize that hiya is already 
            // defined as window.hiya, so it's initialized to undefined here
            var hiya;
            if( false ) {
                hiya = 1;
            }
            document.write( "typeof(hiya) = "+ typeof(hiya) );
        </script>
    </body>
</html>

したがって、すべてを 1 つのスクリプト タグに入れると、コードは次のようになります (JS エンジンが var ステートメントを一番上に移動した後) window.hiya。一番上に移動された変数の後になります。

<html>
    <body>
        <script type="text/javascript">
            var hiya;
            window.hiya = 'hiya';
            if( false ) {
                hiya = 1;
            }
            document.write( "typeof(hiya) = "+ typeof(hiya) );
        </script>
    </body>
</html>
于 2011-01-05T18:24:34.867 に答える
10

コアの問題はここで見ることができますhttp://jsfiddle.net/Raynos/UxrVQ/ IE が確認せずに window.hiya を上書きする理由をまだ調べていません。

[編集]

仕様書より。38ページ:

コード内の VariableDeclaration または VariableDeclarationNoIn ごとに、名前が VariableDeclaration または VariableDeclarationNoIn の識別子である変数オブジェクトのプロパティを作成します。その値は未定義で、属性はコードのタイプによって決まります。宣言された変数の名前を持つ変数オブジェクトのプロパティが既に存在する場合、プロパティの値とその属性は変更されません。

考えられる説明は、変数を宣言するときにグローバル スコープで IE がwindowオブジェクトとグローバル スコープを区別することです。variable objectまたは、オブジェクトに直接プロパティを設定しても、windowオブジェクトに同じプロパティが設定されない場合がありvariableます。正式な JScript 仕様を見つけることができたり、IE のソースがあちこちに転がっている場合は、その癖が何であるかを正確に突き止めることができます。

[/編集]

ウィンドウオブジェクトへのプロパティの書き込みが変数宣言であるかどうかの問題であると指摘した@TimDownと@JuanMendesに感謝します。

問題:

変数宣言はブロックの先頭に移動されます。コードが死んでいても。IE では何らかの理由で hiya をローカル変数として宣言しますが、window に同じ名前のプロパティが格納されているにもかかわらずです。

説明:

何が起こっているかというと、hiya という変数を宣言しています。var ステートメントは自動的にブロックの先頭に削除されます。if ステートメントはブロックではなく、関数です。したがって、コードがブロックで実行されない場合でも、変数は宣言されます。

firefox では、window.hiya が hiya の宣言であることを認識します。

IE では、2 番目のスクリプトの宣言によって上書きされます。

実際に何をしているのか

ファイアフォックスの場合:

// script block 1
var hiya; // window.hiya counts as a declaration
window.hiya = "hiya"; // set

// script block 2
if (false) hiya = 1;
document.write(...)

IE の場合:

// script block 1
window.hiya = "hiya";

// script block 2
var hiya; // redeclared here because window.hiya "isn't" a declaration
if (false) hiya = 1; 
document.write(...)

解決策は単に名前空間です。2 つの場所で同じ名前を使用し、2 つの異なる名前でアクセスしています。別の名前を使用するか、クロージャを使用してローカル スコープを指定してください。

于 2011-01-05T17:24:46.470 に答える
3

発生した原因は次のとおりです。

  1. var声明であること
  2. JS にはブロック スコープはありません
  3. コードが実行される前にステートメントが実行される

したがって、JavaScript はvar何よりも前にステートメントを実行しますが、代入式を評価しないため、hiyaデフォルトで の値になりますundefined

Raynos が既に述べたように、IE は各スクリプトを独自に実行するため、上記の動作はhiya未定義になります。

于 2011-01-05T17:35:15.357 に答える