吉本集の個人ブログ
Web制作の技術について書いています。たまに日記も書きます。

【JS入門】オブジェクトについて Vol.2(グローバルオブジェクト)

2018年1月19日 / category : javascript

グローバルオブジェクト

今までの記事の中でトップレベルという表現を何度か使って来ましたが、このトップレベルもJavaScriptで定義済みのオブジェクトになります。このオブジェクトをグローバルオブジェクトと呼びます。また「コンストラクタ関数について」の記事の中で、コンストラクタ関数を実行すると、その関数の中でthisが新しく生成されますと解説しました。
それではトップレベルでthisが生成されているか確認してみます。

sample.js
console.log( this ); // Window{...}
console.log( typeof this ); // object
console.log( this instanceof Window ); // true
console.log( this === Window ); // false

上の結果から判断すると、トップレベルのthisはオブジェクト型のデータであり、そのオブジェクトの型はWindowオブジェクトであることが確認できます。また、instanceof演算子でWindowオブジェクトと比較するとtrueが返ってくることと、thisとWindowの比較でfalseが返ってくることからthisはWindowオブジェクトのインスタンスであることがわかります。
ここまでを整理すると、グローバルオブジェクトはWindowオブジェクトであるということなります。ただし、これはWebブラウザの環境に限ります。
次のコードを見てみます。

sample.js
let str = 'お腹減った';
console.log( str ); // 'お腹減った'

こちらは改めていうまでもありませんが、コンソール画面で「お腹減った」という文字列を表示します。
トップレベルで宣言した変数をグローバル変数と呼ばれるのは、トップレベルのオブジェクトがグローバルオブジェクトであるためです。Windowオブジェクトであるからという言い方もできます。続いて、次のコードをみてみます。

sample.js
this.str = 'お腹減った';
console.log( str ); // 'お腹減った'

thisはオブジェクトなので、プロパティを追加することができます。プロパティstrに「お腹減った」文字列を代入し、this.strではなく、単にstrを指定するだけで問題なく参照ができています。これはthisが省略されているためです。

sample.js
var str = 'お腹減った';
console.log( this.str ); // 'お腹減った'

こちらも期待通りだと思います。トップレベルで宣言した変数は、thisのプロパティとなります。ここでvar宣言にしているところに注目してください。

sample.js
let str = 'お腹減った';
console.log( this.str ); // undefined

var宣言をlet宣言に変更したところ参照できなくなってしまいました。let宣言とconst宣言はブロックスコープです。ブロックスコープは変数を定義しないことになります。ブロックスコープはあくまでそのブロック内で使用できる変数です。

sample.js
let arr = new Array();

上のコードは、変数arrにArrayオブジェクトのインスタンスを代入しているコードです。それではこのArrayオブジェクトはどこで定義されているでしょうか。

sample.js
console.log( this.Array ); // ƒ Array() {...}

これで参照ができました。もちろんthisを省略しても参照はできます。このことでWindowオブジェクト以外のオブジェクトは、全てWindowオブジェクトの中に定義されていることがわかります。

sample.js
window.open(url,name);

上のようなコードをこれまでに目にしたことがあるかもしれません。メソッドopenは、Windowオブジェクトのメソッドで新しいウィンドウを開く処理を行います。windowの頭文字が小文字になっていることに注目してください。このwindowはプロパティになります。省略せずに記述すると、this.windowとなります。

sample.js
console.log( this.window ); // Window{...}

実際に確かめてみると参照できます。参照すると、Windowオブジェクトが返ってきました。プロパティwindowは、Windowオブジェクトのプロパティで、自身のWindowオブジェクトを返します。そのため、次の比較もtrueになります。

sample.js
console.log( window === window.window.window ); // true

以上が、グローバルオブジェクト(Windowオブジェクト)についての解説でした。

定義済みのオブジェクトのプロパティは読み取り専用

まずは、自作のオブジェクトを見てみます。

sample.js
function test(){
	this.name = 'テストオブジェクト';
}
let t = new test();
console.log( t.name ); // 'テストオブジェクト'
t.name = 'お腹減った';
console.log( t.name ); // 'お腹減った'

これは期待できた結果だと思います。プロパティnameに初期値として「テストオブジェクト」が代入されており、インスタンスの生成後「お腹減った」に再代入しています。続いて、定義済みのオブジェクトで同じことを試してみます。

sample.js
var str = new String('お腹減った');
console.log( str.length ); // 5
str.length = 10;
console.log( str.length ); // 5

Stringオブジェクトのプロパティlengthは文字列の長さが代入されたプロパティです。同様にインスタンスの生成後に10の数値を再代入してみました。結果は、代入されず5のままになりました。定義済みのオブジェクトのプロパティは読み取り専用だということが確認できましたが、インスタンスに新たにプロパティを追加したもの(Stringオブジェクトから継承していないプロパティ)に関しては、問題なく再代入できます。

sample.js
var str = new String('お腹減った');
console.log( str.name ); // undefined
str.name = '吉本';
console.log( str.name ); // '吉本'

プロパティnameに「吉本」が代入できました。これはStringオブジェクトにプロパティnameが定義されておらず、変数strのインスタンスが新たに追加したプロパティのためです。