KDE.BLOG

web制作で学んだことを記していきます

【JavaScript基礎】グローバルオブジェクトについて

<目次>

グローバルオブジェクトとは

JavaScriptのコードはオブジェクトに格納されている必要があり、その格納するオブジェクトの最上位に位置する単一のオブジェクトがグローバルオブジェクトと呼ばれます。
すべてのJavaScriptの実装環境は必ず一つグローバルオブジェクトを持たなければなりません。
Webブラウザでの実装の場合「window」が、Node.jsの場合は「global」がグローバルオブジェクトとなります。

グローバルオブジェクトは明示して生成することができません。つまりnew演算子では作成できません。
グローバルオブジェクトはJavaScriptコードが解釈され初期化される際に作成され、そのプロパティやメソッドはその時点から使用可能になります。

グローバルオブジェクトの役割

グローバルオブジェクトは、上述のようにJavaScriptによって裏で設定され、組み込みオブジェクトなどのネイティブコードを格納しています。
また、ユーザー定義のコードを保持できるように準備されています。

下記は実際に、定義した値がwindowオブジェクトに保持されているか確認しています。(実行環境によってはconsole.log()の結果が異なる場合があります)

var myString1 = 'myString';
var myFunction1 = function() {};

myString2 = 'myString';
myFunction2 = function() {};

console.log(
    'myString1' in window,   // true
    'myFunction1' in window, // true
    'myString2' in window,   // true
    'myFunction2' in window  // true
);

グローバルオブジェクトのプロパティとして保持されているのが確認できました。
このようにJavaScriptを書くときはグローバルオブジェクトのコンテクストに記述しているということを念頭に入れておく必要があります。
でないと、今後コードが複雑化していったときにグローバル汚染により思わぬバグなどを生み出す可能性があります。

定数と関数

グローバルオブジェクトは、グローバルな関数と定数を1つのオブジェクトに集めておくための組み込みオブジェクトです。
(Global オブジェクト (JavaScript) - MSDN - Microsoftより)

これらはどこからでも呼び出せてすぐに使えるメンバです。

グローバル変数とグローバルプロパティ

基本的に、var演算子を使って変数を宣言するとその変数はグローバル変数となり、var演算子を使わないとグローバルプロパティとなります。
両者にはわずかな違いが違いがあります。

var演算子を伴う場合

グローバルスコープでvarを使って変数宣言するとグローバル変数の宣言となり、同時にグローバルプロパティを生成します。

var prop = 1;
console.log(window.prop); // 1

var演算子を伴わない場合

対して場所を問わずにvarなしで変数定義(prop = 1;)をすると、まずスコープチェーンをたどってpropを検索してpropが存在すれば1の代入を試みます。
しかしpropが見つからなかった場合グローバルスコープにpropプロパティを追加します。(グローバルプロパティの生成)

// 関数はスコープを作ります
var myFunc = function() {
    prop = 1;
}();

console.log(window.prop); // 1

両者の違い

上記2つの方法は同じ実行結果となっていますが、違いがあります。

var演算子を使って変数を宣言する場合、DontDelete属性(ECMAScriptで定義されている内部属性)を持ったプロパティを追加します。
対して、var演算子を使わない場合はDontDelete属性は付与されません。

DontDelete属性を持っていると、delete演算子で削除ができません。

結果としては、グローバル変数はdelete演算子で削除することができず、グローバルプロパティはdelete演算子で削除ができます

var prop1 = 1;
prop2 = 2;

delete prop1;
delete prop2;

console.log(prop1); // 1
console.log(prop2); // エラー(prop2 is not defined)

グローバルオブジェクトへのアクセス

グローバルオブジェクトへのアクセス方法には2つ方法があります。

  1. グローバルオブジェクト名を明示する
  2. グローバルスコープでthisを使う
var prop = 1;

var window1 = window;
var window2 = this;

console.log(window1.prop); // 1
console.log(window2.prop); // 1

(ただstrictモードや、ES2015ではグローバルスコープでのthisはundefinedを返す場合があります。
その辺りはまた後日まとめたいと思います。)

windowを明示しない方がわずかに処理が速い

グローバルプロパティとして格納されているものであれば、window.propと書かずに、propだけで呼び出すことが可能で、その方が実はわずかに処理速度が速いそうです。
なので明らかにグローバルプロパティだと分かるネイティブのグローバル関数や定数に関してはwindowを書かかない方がベターだと思われます。

しかしユーザー定義のプロパティであれば、複雑なコードや規模が大きい開発であれば、他の人が見たときにwindowと明示されていた方が、これはグローバルプロパティなんだと分かりやすいメリットもあるので、うまく使い分けると良いように感じます。

参考