IE が window.ABC 変数を無効にするのはなぜですか?
-
25-09-2019 - |
質問
次のコード ブロックを実行すると、FF と Chrome の出力が表示されます。 typeof(hiya) = string
IE7/8出力時 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>
以下のそれぞれを実行すると、問題が解決します。
- すべてをひとつにまとめること
<script>
ブロック。 - の削除
if
ブロック。 - 名前の変更
var hiya = 1
にvar hiya2 = 1
. - 名前の変更
var hiya = 1
にwindow.hiya = 1
. - 名前の変更
var hiya = 1
にhiya = 1
.
何が起こっている? IE にスコープに関するバグはありますか?
解決
IEはバカだからそれを認識しない window.varName
そして var varName
場合によっては同じ変数にアクセスします。
新しいスクリプト タグが見つかると、まず var で宣言されたすべての変数が初期化されます。var ステートメント (「hiya」に初期化する部分) は実行されません。それを未定義に初期化するだけです。ただし、以前に var で宣言されていた場合は、それは行われません。
コードが単一の script タグ内にある場合、このエラーは発生しません。また、hiya の最初の宣言が var で行われた場合、このエラーも発生しません。
具体的には、2 番目のスクリプト タグで、IE はまず var ステートメントを探し、var を見つけます。 var hiya = 1
;次に、hiya は以前に var ステートメントで初期化されていないと表示され (IE は愚かなので、他のブラウザは window.hiya が同じことを行うことを認識します)、hiya を初期化し、コードを実行する前に window.hiya を上書きします。
可能な解決策:
- コードを同じ script タグ内に収めてください
- 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 ステートメントを先頭に移動した後)。したがって、IE がそれを台無しにする方法がないことがわかります。 window.hiya
割り当ては、先頭に移動された var の後に配置されます。
<html>
<body>
<script type="text/javascript">
var hiya;
window.hiya = 'hiya';
if( false ) {
hiya = 1;
}
document.write( "typeof(hiya) = "+ typeof(hiya) );
</script>
</body>
</html>
他のヒント
核心的な問題はここで見ることができます http://jsfiddle.net/Raynos/UxrVQ/ IE が確認せずに window.hiya を上書きする理由はまだわかりません。
[編集]
仕様より。38ページ:
コード内の各変動範囲または変動範囲内で、変数オブジェクトのプロパティを作成します。その名前は、変動範囲またはvariabledeClarationNoinの識別子であり、その値は定義されておらず、属性がコードのタイプによって決定されます。宣言された変数の名前を持つ変数オブジェクトのプロパティがすでにある場合、プロパティとその属性の値は変更されません。
考えられる説明としては、IE がグローバル スコープで次のものを区別しているということです。 window
オブジェクトと variable object
変数を宣言するときのグローバル スコープの場合。または、 window
オブジェクトが直接同じプロパティを設定しない可能性があります。 variable
物体。正式な JScript 仕様を見つけることができれば、または IE のソースが手元にあれば、何が問題なのかを正確に突き止めることができます。
[/編集]
@TimDown と @JuanMendes が、ウィンドウ オブジェクトへのプロパティの書き込みが変数宣言であるかどうかの問題であると指摘してくれたことに感謝します。
問題:
変数宣言はブロックの先頭に移動されます。たとえコードが死んでいたとしても。IEでは、ウィンドウに保存されている同じ名前のプロパティでクラスを作成しているにもかかわらず、何らかの理由でhiyaをローカル変数として宣言します。
説明:
何が起こっているのかというと、hiya という変数を宣言しているということです。var ステートメントはブロックの先頭から自動的に削除されます。if ステートメントはブロックではありませんが、関数はブロックです。したがって、コードがブロック内で実行されなかった場合でも、変数は宣言されたままになります。
Firefox では、window.hiya が hiya の宣言であることを認識します。
IE では、2 番目のスクリプトの宣言によって上書きされます。
実際に何をしているのか
Firefoxの場合:
// 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 つの異なる名前でアクセスしています。別の名前を使用するか、クロージャを使用してローカル スコープを指定します。
あなたが遭遇した問題の原因は次のとおりです。
var
声明であること- JSにはブロックスコープがない
- コードが実行される前にステートメントが実行されます
つまり、JavaScript が var
ステートメントは他の何よりも前に実行されますが、代入式は評価されません。 hiya
デフォルトでは次の値になります undefined
.
Raynos がすでに述べたように、IE は各スクリプトを独自に実行するため、上記の動作は次のようになります。 hiya
未定義であること。