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

【JS入門】オブジェクトの作り方 Vol.1(オブジェクト初期化子)

2018年1月22日 / category : javascript

オブジェクトについて解説してきましたので、今回はオブジェクトの作り方について解説していきます。
オブジェクトの作り方は大きく分けて次の3つの方法があります。

1. オブジェクト初期化子
2. コンストラクタ関数
3. class定義

オブジェクト初期化子を使用したオブジェクト生成

今回の記事では、最初の「オブジェクト初期化子」での作り方を解説します。
オブジェクト初期化子とは、次の3つのいずれかの構文を使用してObjectオブジェクトを初期化して新たにオブジェクトを生成する方法です。

1. new Object()
2. Object.create()
3. リテラル記法(オブジェクトリテラル)

上の3番目のリテラル記法(オブジェクトリテラル)についてですが、簡単に言ってしまうと、オブジェクトのプロパティを中括弧{}で囲んで書く構文です。

let object = {}

上の構文で作成した値(データ)はオブジェクトを返します。中括弧{}の中が空なので、空のオブジェクトです。
このオブジェクトについては、以前の記事「データには型がある(オブジェクト型について)」でも解説しています。
それではリテラル記法(オブジェクトリテラル)で生成したオブジェクトのコードを見てみます。

sample.js
let obj = {
	txt: 'お腹減った',
	getMessage: function(){
		return this.txt;
	}
}
console.log( obj.txt ); // 'お腹減った'
console.log( obj.getMessage() ); // 'お腹減った'

上のコード結果は想像できたと思います。変数objの値(データ)は、リテラル記法(オブジェクトリテラル)で記述されたオブジェクトであり、プロパティtxtには「お腹減った」の文字列が代入されており、プロパティgetMessageは、無名関数が代入されているのでメソッドとなります。メソッドgetMessageの関数文を見ると、return文でプロパティtxtを返しています。
それではこのオブジェクトのプロトタイプはどうなっているでしょうか。

sample.js
let obj = {
	txt: 'お腹減った',
	getMessage: function(){
		return this.txt;
	}
}
console.log( typeof obj ); // object
console.log( obj.__proto__ === Object.prototype ); // true
console.log( obj.prototype ); // undefined
console.log( obj.constructor === Object ); // true

上の結果は想像できたでしょうか。変数objの型はobjectです。これは想像できたと思います。
変数objの継承元のプロトタイプ(プロパティ__proto__)は、Object.prototypeになります。これも想像できたと思います。
プロパティprototypeについてはどうでしょうか。
変数objはリテラル記法(オブジェクトリテラル)で記述されていますが、次の記述と同じです。

sample.js
let obj = new Object({
	txt: 'お腹減った',
	getMessage: function(){
		return this.txt;
	}
});

new Object()を使用しています、これはオブジェクト初期化子の構文のひとつです。
この構文を見ると、変数objがObjectオブジェクトのインスタンスだということがわかると思います。
インスタンスはプロトタイプを継承したオブジェクトですので、プロパティprototypeを保持していません。そのため上の結果でundefinedとなっています。さらに、変数objはObjectオブジェクトのインスタンスですので、プロパティconstructor(コンストラクタ)に継承元のオブジェクト(Objectオブジェクト)が代入されています。

ここまでは理解できたでしょうか。次に図にまとめてみます。

ここからまだ解説していなかった機能を紹介します。
リテラル記法(オブジェクトリテラル)には、get構文・set構文という構文を使用することができます。

get構文・set構文

get構文をgetter(ゲッター)、set構文をsetter(セッター)という呼び方もします。まずは、それぞれ構文を見てみます。

let object = {
	get プロパティ名(){
		関数文
	}
}

let object = {
	set プロパティ名(引数){
		関数文
	}
}

オブジェクトのプロパティを参照した際に、getter/setterで設定した関数が実行されます。ただし、あくまでプロパティだという点に注意し、次のgetter/setterを使用したコードを見てみます。

sample.js
let obj = new Object({
	txt: 'お腹減った',
	get message(){
		return this.txt;
	},
	set message(value){
		this.txt = value;
	}
});
console.log( obj.message ); // 'お腹減った'
obj.message = 'お腹は減っていない';
console.log( obj.message ); // 'お腹は減っていない'

getter/setterを使用したコードです。使用しているプロパティ名がgetter/setterともにmessageになっていますが、同じである必要はありません。ただ、get構文はプロパティtxtを返しており、set構文は引数をプロパティtxtに代入しており、ともにプロパティtxtを参照・設定と対になっている関係性がありますので、同じプロパティ名にするという書き方が、この例に関しては一般的かもしれません。
get構文で参照する記述ですが、関数になっているので、obj.message()と記述したくなりますが、あくまでプロパティ扱いですので、obj.messageになります。
set構文も同様に、obj.message(‘お腹は減っていない’)と記述したくなりますが、obj.message = ‘お腹は減っていない’という記述になります。
また、このgetter/setterを削除したい場合は、delete構文を使うことで可能です。

sample.js
let obj = new Object({
	txt: 'お腹減った',
	get message(){
		return this.txt;
	},
	set message(value){
		this.txt = value;
	}
});
console.log( obj.message ); // 'お腹減った'
delete obj.message;
console.log( obj.message ); // undefiend

ここまでで、オブジェクト初期化子でのオブジェクトの生成方法のうち、new Object()とリテラル記法(オブジェクトリテラル)の解説が終わりました。残りのObject.create()について解説します。

let object = Object.create(プロトタイプ)

create関数は、Objectオブジェクトで定義されている関数です。引数にプロトタイプを指定することで、オブジェクトを生成してくれます。

プロトタイプとインスタンスは同じ構造になっていますので、インスタンスをプロトタイプとして使用することができます。上のobjインスタンスを使用して、新たにオブジェクトを生成してみます。

sample.js
let obj = {
	txt: 'お腹減った',
	get message(){
		return this.txt;
	},
	set message(value){
		this.txt = value;
	}
};
let o = Object.create( obj );
console.log( o ); // {}
console.log( o.__proto__ === obj ); // true
console.log( o.constructor === Object ); // true
console.log( o === obj ); // false

リテラル記法(オブジェクトリテラル)で作成したオブジェクト(変数obj)をObjectオブジェクトのcreate関数の引数に代入し、新たにオブジェクトを生成しました。
変数objは、上で解説した通りObjectオブジェクトのインスタンスになります。Objectオブジェクトのcreate関数の引数にはプロトタイプを代入する必要がありますが、インスタンスも同じ構造ですので、プロトタイプとして使用することができます。
Objectオブジェクトのcreate関数で返ってきたオブジェクトを見てみます。
変数objをプロトタイプとして継承しているので、プロパティ__proto__との比較でtrueが返ってきます。
また、変数objのコンストラクタ関数(constructor)は、Objectオブジェクトを継承していますので、Objectオブジェクトとの比較でtrueが返ってきています。
最後の比較では、変数oと変数objを比較しています。falseが返ってきていることから別々のオブジェクトであるということが確認できます。

以上が、オブジェクト初期化子を使用したオブジェクト生成の解説になります。次回は残りの「コンストラクタ関数」「class定義」のいずれかを解説できればと思っています。