doc.open()
を使用してドキュメントへの参照を取得します)onload
ハンドラーとしてアタッチされます(<body onload="...">
をiframeに書き込むことにより)。今私が困惑しているのは、(実行中の)onloadハンドラー内のグローバル(ウィンドウ)およびドキュメントオブジェクトが、スクリプトノードを介して追加されたJavaScriptを介して実行される同じオブジェクトと異なることです。
<!doctype html>
<html>
<head>
<script>
(function(){
var dom,doc,where,iframe;
iframe = document.createElement('iframe');
iframe.src="javascript:false";
where = document.getElementsByTagName('script')[0];
where.parentNode.insertBefore(iframe, where);
doc = iframe.contentWindow.document;
var _doc = document;
doc.open()._l=function() {
// the window object should be the one that doc is inside
window.vanishing_global=new Date().getTime();
var js = this.createElement("script");
js.src = 'test-vanishing-global.js?' + window.vanishing_global;
window.name="foobar";
this.foobar="foobar:" + Math.random();
document.foobar="barfoo:" + Math.random();
// `this` should be the document object, but it's not
console.log("this == document: %s", this == document);
console.log("this == doc: %s", this == doc);
// the next two lines added based on @Ian's comment below
console.log("_doc == document: %s", _doc == document);
console.log("_doc == doc: %s", _doc == doc);
console.log("name: " + window.name + "\n" + "window.vanishing_global: " + window.vanishing_global + "\ntypeof window.vanishing_global: " + typeof window.vanishing_global + "\ndocument.foobar: " + document.foobar);
this.body.appendChild(js);
};
doc.write('<body onload="document._l();"></body>');
doc.close();
})();
</script>
</head>
<body>
</body>
</html>
test-vanishing-global.js
があります:console.log("name: " + window.name + "\n" + "window.vanishing_global: " + window.vanishing_global + "\ntypeof window.vanishing_global: " + typeof window.vanishing_global + "\ndocument.foobar: " + document.foobar);
これらの2つのファイルをディレクトリに入れ、ブラウザーでHTMLを開きます(最新のChromeとFirefoxでテスト済み、両方で同じ結果になります)。
this == document: false
this == doc: true
_doc == document: true
_doc == doc: false
name: foobar
window.vanishing_global: 1366037771608
typeof window.vanishing_global: number
document.foobar: barfoo:0.9013048021588475
name:
window.vanishing_global: undefined
typeof window.vanishing_global: undefined
document.foobar: foobar:0.5015988759696484
ハンドラー内のthis
オブジェクトは、ドキュメントオブジェクトでなければなりません。 It isドキュメントオブジェクトですが、内部で実行されるドキュメントと同じドキュメントオブジェクトではありません(親ドキュメントとも同じではありません)。ハンドラー内のウィンドウオブジェクトも、ページに読み込まれたJavaScriptで実行されるウィンドウオブジェクトとは異なります。
誰が何が起こっているのか、実際のウィンドウオブジェクトへの参照を取得する方法、または少なくとも同じグローバルコンテキストからグローバル変数を宣言して参照する方法を知っていますか?
このiframeは同じドメイン上にあるため、クロスドメインの問題はありません。誰かがdocument.domain
を設定すると問題が発生しますが、このサンプルコードでは行われていません。
親ページですべてを宣言しています。したがって、window
およびdocument
への参照は、親ページのものです。 iframe
の処理を行う場合は、iframe || iframe.contentWindow
を使用してwindow
にアクセスし、iframe.contentDocument || iframe.contentWindow.document
を使用してdocument
にアクセスします。
何が起こっているのか、おそらく「レキシカルスコープ」という言葉があります: レキシカルスコープとは?
スコープの唯一のコンテキストはこれです。そして、あなたの例では、メソッドの所有者はdoc
であり、これはiframe
のdocument
です。それ以外は、既知のオブジェクトを使用するこの関数でアクセスされるものはすべて親です(関数で宣言されていない場合)。関数が別の場所で宣言された場合は別の話になりますが、親ページで宣言されます。
これは私がそれを書く方法です:
(function () {
var dom, win, doc, where, iframe;
iframe = document.createElement('iframe');
iframe.src = "javascript:false";
where = document.getElementsByTagName('script')[0];
where.parentNode.insertBefore(iframe, where);
win = iframe.contentWindow || iframe;
doc = iframe.contentDocument || iframe.contentWindow.document;
doc.open();
doc._l = (function (w, d) {
return function () {
w.vanishing_global = new Date().getTime();
var js = d.createElement("script");
js.src = 'test-vanishing-global.js?' + w.vanishing_global;
w.name = "foobar";
d.foobar = "foobar:" + Math.random();
d.foobar = "barfoo:" + Math.random();
d.body.appendChild(js);
};
})(win, doc);
doc.write('<body onload="document._l();"></body>');
doc.close();
})();
win
およびdoc
をw
およびd
としてエイリアシングする必要はありません。スコープの誤解により混乱が少なくなる場合があります。このように、それらはパラメータであり、iframe
のものにアクセスするにはそれらを参照する必要があります。親にアクセスしたい場合は、window
とdocument
を使用します。
document
(この場合はdoc
)にメソッドを追加することの意味がわかりませんが、win
に_l
メソッドを設定する方が意味があります。そのように、物事は接頭辞なしで実行することができます... <body onload="_l();"></body>
など