Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
JavaScript
応用編
- トップページ
- JavaScript応用編 - windowオブジェクトとグローバルの実態について
windowオブジェクトとグローバルの実態について
皆様どうもおはこんばんにちは。
さて、続きまして『windowオブジェクト』とか『グローバル』の実態について色々とやっていきましょう。
まずちょっとJavaScriptのスコープについておさらいをしておきます。JavaScriptのローカルスコープは「関数オブジェクトの中」しか存在しません。なのでスコープについては関数オブジェクトの外か中かだけ注目しておけばOKです。
var f = function(){ // これはグローバル関数です。 var a = 0; // これはローカル変数です。 var _f = function(){ // これはローカル関数です。 }; function _fn(){ // function文でも同じです。こちらもローカル関数になります。 } _f(); // 実行できます。 _fn(); // 実行できます。 }; var b = 1; // これはグローバル変数です。 f(); // 実行できます。 _f(); // エラーです。 _fn(); // エラーです。 console.log(a); // これはエラーです。 console.log(b); // 数値『1』が出力されます。
さて、ではここで「関数の中でグローバルな値とかプロパティとかを定義するにはどうすの?」という問題について考えてみましょう。
JavaScriptには他の言語のように「グローバル宣言用の記述」みたいなのは用意されていません。なので他の言語とはちょっと違った形で定義する必要があります。
まず思いつくのは『var』を記述しないことです。『var』を抜いて定義してしまえばそれは『グローバル』として扱われるのでそれを利用します。こんな感じですね。
(function(){ a = 0; // 『var』を抜いて定義します。 })(); console.log(a); // 数値『0』が出力されます。
※『(function{})()』は『即時関数』と呼ばれます。詳しくはこちらへどうぞ。
しかし、ここがちょっとややこしいのですが『var』を記述するかしないかで『グローバル』を定義するやり方は「意図して『グローバル』として定義したのか」、それとも「『var』の書き忘れなのか」、という判断が付きづらいという背景があります。
なのでJavaScriptで『グローバル』として定義する場合に一番オススメしたい方法が『window.』を付けてしまうということです。
(function(){ window.a = 0; // 『window.』を付けることで「意図してグローバルとして定義したぜ!」ってことをめっちゃアピールすることができます。計画通りです。 })(); console.log(a); // 数値『0』が出力されます。
これめっちゃオススメなんで是非使ってみてください。
さて、ここでちょっと疑問が湧いたと思います。なぜ『window.』を付けると『グローバル』として扱われるのか、というところですね。
というわけでJavaScriptの『グローバルの実態』についてみていきましょう。
まずJavaScriptには『windowオブジェクト』ってやつがいます。こいつは「ブラウザそのもの」のような奴です。JavaScriptに元々用意されている色々なプロパティやメソッドの親にあたるような存在ですね。なのでJavaScriptをブラウザ上で実行させるならば必ず存在しています。JavaScriptの世界のゴッドファーザーです。
console.log(window); // windowオブジェクトを出力します。こいつはブラウザ上で実行させたならば必ず存在しています。
なぜこういう仕組みになっているのかというと「JavaScriptはそういう風に設計されているから」でございます。ここは深く考えなくて良いです。解決したいのであるならば開発者に聞いてみてください。
そして『windowオブジェクト』のプロパティやメソッドにアクセスするときの『window.』って記述は省略できるようになっています。
なので皆様が良く使用しているであろう『document.getElementById()』などの処理は、正確に記述すると『window.document.getElementById()』だったりします。
window.document.getElementById("test"); // 正確に記述するとこうなります。
そんでもってまた適当にグローバル変数を定義してみましょう。
a = 0; // グローバル変数『a』を定義します。
そしたら『windowオブジェクト』の中身を覗いてみましょう。
a = 0; // グローバル変数『a』を定義します。 console.log(window); // 『windowオブジェクト』を出力させてみます。
するとあら不思議。こんな結果が返って来ます。
// 長いので省略... // ... XPathResult:XPathResult() XSLTProcessor:XSLTProcessor() __google_ad_urls:Xp a:0 // ここに注目して下さい。 adsbygoogle:Object alert:alert() // 長いので省略... // ...
なんと『windowオブジェクト』に『a』っていうプロパティが追加されています。
というわけでもう分かりましたね。実はJavaScriptのグローバル変数の実態はwindowオブジェクトのプロパティだったりします。そんでもってグローバル関数の実態はwindowオブジェクトのメソッドになります。
なので以下の処理は同義になります。
// これらは同義です。 a = 0; window.a = 0; // これらは同義です。 f = function(){ }; window.f = function(){ }; function f(){ }
これが『window.』を付けるとグローバルな要素として定義できる理由でした。
そんでもって、上記の挙動を利用したこんなテクニックが良く使用されてます。以下は『#test』というHTML要素があったときにだけグローバル関数を定義しています。
(function(){ // 即時関数でラップします。これでグローバル汚染を防いでいます。 var a = document.getElementById("test"); // これはローカルです。 if(a){ // 『a』が存在したときだけグローバル関数『f』を定義します。 window.f = function(){ // 適当な処理... }; } })();
即時関数でラップしてローカルスコープで処理を進めつつ、必要な時にだけグローバル関数を生成するというテクニックですね。
これは色々なライブラリなどで良く使用されている手法になりますので覚えておきましょう。
HTML要素にid属性が記述している場合は自動で『windowオブジェクト』にそのid属性の値と同じ名前のプロパティが追加されちゃったりします。
<div id="test"></div> <script> console.log(window.test); // 『window.test』っていうプロパティが自動で生成されます。この中身は『div#test』のHTML要素になります。 </script>
なのでJavaScriptからそのまま『windowオブジェクト』経由で操作することとか出来ちゃいますが、これは基本的に使用しない方が無難です。
というのも、先にid属性の値と同じ名前のプロパティやメソッドがすでに定義されていた場合は自動追加されないからです。
<script> window.test = 0; // 『window.test』っていうプロパティを先に定義しちゃいます。 </script> <div id="test"></div> <script> console.log(window.test); // 先に『window.test』が定義されているため、この中身は『div#test』のHTML要素になりません。 </script>
あんまり使用する機会はないかと思いますが、一応頭の隅にでも置いておいて下さい。
というわけで以上になります。続いての記事では『this』について色々とやっていきましょう。ではこの辺で失礼致します。
この記事は桜舞が執筆致しました。
著者が愛する小型哺乳類 |
桜舞 春人 Sakurama HarutoISDN時代から様々なコンテンツを制作しているちょっと髪の毛が心配な東京在住のプログラマー。生粋のロングスリーパーで、10時間以上睡眠を取らないと基本的に体調が悪い。好きなだけ寝れる生活を送るのが夢。ゲームとスポーツと音楽が大好き。誰か髪の毛を分けて下さい。 |
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。