m2

グローバルオブジェクトの参照はも function 宣言時に決まる

以前「window オブジェクトを汚さないネタ」で疑問に思ったので検証しました。
parent.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>Window テスト(Parent)</title>
<script type="text/javascript">
window.name='parent';
function hello(){
    alert('hello:'+window.name);
}
function openChild(){
    var w=open('child.html','','width=400,height=400');
    w.parentHello=hello;
}
</script>
</head>
<body>
<p><button onclick="openChild()">openChild</button></p>
</body>
</html>

child.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>Window テスト(Child)</title>
<script type="text/javascript">
window.name='child';
function hello(){
    alert('hello:'+window.name);
}
window.parentHello2=parentHello;
window.parentHello3=function(){
    parentHello();
};
window.parentHello4=function(){
    parentHello.call(window);
};
window.parentHello5=function(){
    eval('('+parentHello.toString()+')()');
};
</script>
</head>
<body>
<p><button onclick="hello()">childHello</button> 「hello:child」</p>
<p><button onclick="parentHello()">parentHello</button> 「hello:parent」</p>
<p><button onclick="parentHello2()">parentHello2</button> 「hello:parent」</p>
<p><button onclick="parentHello3()">parentHello3</button> 「hello:parent」</p>
<p><button onclick="parentHello4()">parentHello4</button> 「hello:parent」</p>
<p><button onclick="parentHello5()">parentHello5</button> 「hello:child」</p>
</body>
</html>

結果は表題の通り「グローバルオブジェクトの参照は function 宣言時に決まる」ようです。OperaFirefoxIE で同じ結果になったのでほっとしました。

で、これはやはりクロージャが作用しているものだと思われます。

関数内に出現するフリー変数(関数内で宣言されていない変数)の解決の際、実行時の環境ではなく、関数を定義した環境の変数を参照する機能。

僕はこれを「関数を定義した環境のローカル変数」と解釈していたのですが、グローバルオブジェクトも例外ではないようです。

これを「特定の window オブジェクトに依存しない書き方」にするには、例えば以下のようにします。
parent.html

(略)
<script type="text/javascript">
(function(){
    var win=window;
    window.LIB = {
        setEnvironment: function(newWin){
            win=newWin;
        },
        flexibleHello : function(){
            win.alert('hello:'+win.name);
        }
    }
})()
()
function openChild(){
    var w=open('child.html','','width=400,height=400');
    w.parentHello=hello;
    w.LIB=window.LIB;
}
</script>
(略)

child.html

(略)
<p><button onclick="LIB.flexibleHello()">flexibleHello</button> 「hello:parent」setEnvironment後は「hello:child」</p>
<p><button onclick="LIB.setEnvironment(window);LIB.flexibleHello()">setEnvironment→flexibleHello</button> 「hello:child」</p>
(略)

実行前にグローバルオブジェクトをライブラリに渡して、ライブラリ内ではグローバルオブジェクトに一切アクセスしないというやり方です。
こうしておけば複数の window 間でライブラリを共有できるのですが、なかなかそのようなライブラリは見かけませんね。まあそれぞれの window でライブラリをロードすればいいだけなので問題は無いのですけれども。