てくてくテック

【JavaScript】Windowオブジェクトって結局何なの...?

たかぽん
どーも!

たかぽんです!

今回はJSを使ってるとよくみるwindow.hogeみたいなやつのwindowってなんなの...?

っていう疑問がいつまでたっても拭えずにいたため...

重い腰を上げて少し調べてみようと思います!

どんな使い方されてるの?

まずは実際にどんな風に使われているのかをみていこうかなぁと思います。

例えばですが、jsでバグを探す時によく使うalert...

たまに

window.alert('hoge');

と使われていたりしませんか・・・?

他にも

window.open('hoge');

みたいなのも結構見かけるかもしれません...!

ただ、どちらともwindowは無くても動いたりします...w

一体全体なんなんだw

windowとは・・・?

さて...それではMDN Web Docsのwindow解説ページを読んでくるとしましょう...!

Window インターフェイスは、DOM document を収めるウィンドウを表します。documentプロパティは、そのウィンドウに読み込まれた DOM の document オブジェクト を指します。

MDN Web Docs

ふむ...

ここから察するにWindowが持つdocumentプロパティにはページのDOMの要素が入っていて、documentを使うことでいろんなDOM要素(head, body, p, div等)にアクセスができるということですね。

例えば検証画面からwindow.document.bodyとするとそのページのbody要素が得られますね。

せっかくなので検証画面で調べてみましょう。

今回はGoogle Chromeを使わせてもらいます。(他のブラウザでも似た感じでできるかと!

ブラウザ上で右クリックを押して、検証を選択します。

検証画面を開く
右上にこんな感じのがでるので>>を選択してConsoleを選ぶ

画面が大きい場合は>>で省略されず、普通に横並びにConsoleと出ている場合も有ります。

Consoleを開いたらすぐ下の画面に

"window.document.body"

と入力してみましょう。

window.document.bodyとdocument.bodyでbody要素を参照してみた

出てきましたね。

body要素。

ちなみに、省略もできました。

どうやらまっさらな状態だとwindowのスコープがデフォルトみたいです。

ユーザーは常にwindowと同じ階層にいるので、参照する場合も現在位置からdocument、そしてその下にあるbodyをといった感じでアクセスできるみたい。

ちなみに、普段はあまりしないのですが、windowは自身を参照することができるため、window.document.bodyでもうまくいくみたいです。

そう考えると、何もしなくてもwindowにいるからわざわざ参照する意味ない気もしますね...w

スコープ...?よくわかんない...

基本的には何かを参照ができる範囲といった意味合いが強いです。

ただ、スコープについて詳しく説明しようとすると長くなってしまいます...

もし、スコープという言葉が難しい場合は、以下のように考えてみてください。

ピラミッドの一番上の部屋にwindowという部屋があって、その下にdocumentという部屋があって、その部屋の下にはDOM入りのオブジェクトが置いてある部屋が有ります。

僕らは基本的に一番上の部屋で作業します。

なので、documentという部屋にいきたい時には"ドキュメント部屋いきたい〜!"と伝えないといけないので

"document"(documentにいきたい!)あるいは"window.document"(今windowいるんだけど、これからdocumentいきたい!)と指定してあげます。

自分のいる位置はwindowなので、windowいるんだけど、っていうのは伝えなくても大丈夫です。

さらにその下のDOM入りのオブジェクトがある部屋までいきたいなら目的のDOMの種類を添えて、

"document.head"あるいは"window.document.head"と指定してあげればいいんです。

一気に二階駆け下りることは基本的にはしません(窓の外から頑張って降りたりしないですよねw)ので、"window.head"(今windowいるんだけど、documentは行かなくていいから、headいきたい!)といった書き方はできません。

window.headだとundefined

わかりやすい図があったのでぜひこちら参照してみてください。

Window オブジェクトや Document オブジェクト、DOMなど

Windowがどんなものなのかはなんと無くわかりましたね。

では、引き続き語られているWindowを取得することについて考えていきましょう。

特定のドキュメントが属するウィンドウは、document.defaultView プロパティを使用して取得できます。

MDN Web docs

”特定のドキュメントが属するウィンドウ”つまり、document.defaultViewプロパティを使用したらまさにwindowが帰ってくるということです。

ちょっと試してみましょう。

document.defaultViewを実行

そのままdocument.defaultViewを実行すると、そのままWindowが返ってきます。

すぐ下に使えるメソッド(window.alertやwindow.closeなど)なんかが表示されていますね。

(一部メソッドはブラウザによって使用不可になっています...window.closeはchromeでは使えません。

もうちょっと面白い例をみてみましょう。

先ほど参照したDOMのbody要素を探してみましょう。

ただし、先ほどとは違い今回は"document.defaultView.document.body"と入力します。

document.defaultView.document.bodyでbodyを参照

一体何が...?w

これすなわち、"document.defaultView" = "window"ととらえていただけるとわかるかと思います。

"(document.defaultView).document.body"は"(window).document.body"と一緒なんです!!!

ということは...?w

document.defaultViewの後にまたdocumentきてるやん...これは...

"document.defaultView.document.defaultView.document.defaultView.document.body"でもうまく行ってしまうんですね...www

エラー出そうだなと思ったんですが...w

ちなみにそうなると今度はwindow.window.window.document.bodyも気になってしまうw

からやってみました。

いけた。

こんな書き方は絶対やめましょうw

JavaScriptのグローバル変数

window グローバル変数はスクリプトを実行しているウィンドウを表しており、JavaScript コードに公開されます。

MDN Web docs

さて、続いてこのように書かれていますね。

windowグローバル変数はJavaScriptコードから参照することができますよってことかな・・・?と。

そしてwindowは実際にスクリプトを実行しているウィンドウを表しているので、JSで参照することで結果としてDOM要素等をいじいじできます!

って感じなのかな・・・?きっと・・・。

windowインターフェイスが持つアイテム

Window インターフェイスは、ユーザーインターフェースのウィンドウの概念とは必ずしも直接関連づかない、さまざまな関数、名前空間、オブジェクト、コンストラクターのホームです。一方、Window インターフェイスはグローバルで使用可能であることが必要な、さまざまなアイテムを含むのに適した場所です。これらの多くは JavaScript リファレンス や DOM リファレンス に文書化しています。

MDN Web docs

らしいです。

ここでいうユーザーインターフェスのウィンドウの概念っていうのはおそらくユーザーとシステムの間にウィンドウが有り、システムが何かを出力(伝える)するという概念です。

それに関連がづかない関数やその他アイテムもwindowインターフェイスがもってますよーってことだと思います。

ちなみに関連づく関数としてはalert関数はそうですよね。

システムがalertによって文字を出力し、僕らユーザーが目で見れるようになります。

逆に関連づかない関数として"Window.outerHeight"プロパティなんかがそうですね。

"Window.outerHeight"はただ値を返すだけで出力や表示の機能は有りません。

Consoleに打ち込めばたしかに値を表示してくれますが、それはConsoleがデバッグのために出力部分を担ってくれるからなんです。

本来のプログラム上では、

"Window.outerHeight"

だけ書いても何も表示されません。

させたいなら、関連づくメソッドと一緒に、

alert("Window.outerHeight");

としてあげればできるようになりますね。

その違いです。

そして、プログラム中のどんな場所でも使える(グローバルな)変数等を定義する場所として適していますと。

実際、windowと同じ階層に変数を定義しておけば基本的にどんな関数の中でもその変数が使えます。

例えば、windowにて定義した変数を階層の違う関数の中で使ってみます。

windowで変数定義し、その値を別で定義した関数の中で定義、そして関数呼び出し

これ少しわかりづらいですね...定義するたびにundefinedが返ってきてますが、特に返す値がないのでそうなっています。

そして定義が終わったら関数を呼び出すとちゃんと値として入って出力されています。

ばっと書くとこんな感じ

var global Value = 'globalValue';

function globalfunction () {
     console.log('I am ' + globalValue);
}

globalfunction();

ただ、基本的に

グローバル変数=いつどこで変更されるかわからりづらい変数

となるため、あまり使わない方がいいです...

できれば極力使わないように意識ましょう。

タブブラウザーについて

タブブラウザーでは、タブの各々が、それ自身の Window オブジェクトを持っています。タブ内で実行している JavaScript から見えるグローバル window は、コードを実行しているタブを常に表します。しかしタブブラウザーであっても resizeTo() や innerHeight など、タブを包含するウィンドウ全体に適用されるプロパティやメソッドがあります。一般的に、タブに属することができないもっともな理由があるものは、代わりにウィンドウに属します。

MDN Web docs

なるほど。

タブブラウザー(googleのタブがたくさんある時とか)ではそれぞれのタブがWindowオブジェクト(DOM構造とかメソッドとか色々持ってるやつ)を持っていますと。

そして、タブ内で実行しているJavaScriptから参照できるグローバルwindowオブジェクトは、常にそのJavaScriptが実行されているタブのwindowオブジェクトみたいです。

そしてタブを含むウィンドウっていうのはおそらく左上の最大化なんかをした時に画面全体のサイズが大きくなりますよね?その時その大きくなってる画面にタブとか、URLとかも含まれていると思います。

それら全てを含んだウィンドウ(画面全体)のことでしょう。

それら全てに作用するメソッドやプロパティも有りますよと。

タブを含むウィンドウ
タブを含まないウィンドウ(laravelタブのwindowオブジェクト)
タブを含まないウィンドウ(タブ2 - google 検索タブのwindowオブジェクト)

ということで、ここで個人的に疑問が...

各タブが持つウィンドウと全体(全てのタブなども含む)のウィンドウはどう違うんだろう...?と...

正直ここは憶測の部分が大きいですが、タブ等の全体の操作もしなければいけないメソッドなどは全体のウィンドウとして、そしてそういった操作が必要ないメソッドなどは各種タブが持つ自身のwindowオブジェクトとして参照しているのかな・・・?と。

そんな使い分けを裏でしてくれているのかな・・・?

ちなみにですが...文中のresizeTo()メソッドですが、複数タブある場合は使えないようになってました...w

resizeTo()の注記

1. window.open で作成されたウィンドウ(またはタブ)しかリサイズ出来ません。
2. ウィンドウが複数のタブを持つ場合、ウィンドウ(またはタブ)のリサイズは出来ません。

MDN web docks - 注記

タブ包含した画面全体リサイズできなくなってますね...w

もう一つの方は特に書かれていませんでしたが、どうやらchromeでは動かないみたい。

まぁ、このWindowの違いに関してはあまり意識しなくてもよさそうな気はします。

まとめ

はい、というわけで!今回は謎だったwindowについて調べました。

個人的にいまだにちょっぴり疑問の残る箇所も有りますが、結論として省略できるならwindowはいらない!w

そして、基本的には各ページの頂点にあるものがwindowで、その下にdocumentがぶら下がってる。

もしもタブも含めた操作を必要とする場合はもう少し詳しく調べ直しが必要!

って感じでした。

MDNもそうなんですが、公式ドキュメントとか、しっかりした有志によるドキュメントって難しい単語やら言葉が多くて難しいですよね...

都度こういう記事も書いていけたらいいかなぁと思います。

それでわ!

モバイルバージョンを終了