JavaScript勉強会

JavaScriptの学習日記

オブジェクトの生成 【開眼!JavaScript】

JavaScriptの学習メモ。

今日は「開眼!JavaScript」の第1章を読んでみます。

 

jsstudy.hatenablog.com

 

 

1.1 オブジェクトの生成

(p.1)

JavaScriptの世界では、オブジェクトが王様です。

この世界では、ほぼすべてがオブジェクトそのものか、もしくはオブジェクトのようにふるまいます。

オブジェクトを理解すると、きっとJavaScriptを理解できることでしょう。

まずはJavaScriptのオブジェクト生成方法を調べてみましょう。

オブジェクトは、名前のついた値(プロパティ)の集合体を格納するコンテナです。

 

オブジェクトとは何か?

まず、「オブジェクト」という用語の意味を確認してみます。

JavaScript オブジェクト 意味 - Google 検索

 

(参考)

オブジェクトを利用する - JavaScript | MDN

JavaScript におけるオブジェクトはプロパティの集まりからなり、またそのプロパティは名前(あるいはキー)と値との関連付けから成り立っています。

プロパティの値を関数にすることもでき、これはいわゆるオブジェクトのメソッドとなります。

 

オブジェクト指向の用語「プロパティ」「メソッド」 - JavaScript勉強会

データと処理をまとめて束にしたものが「オブジェクト」です。

データ → オブジェクトの「状態」を表し、「プロパティ」と呼ばれる。

処理 → オブジェクトの「操作」を表し、「メソッド」と呼ばれる。

 

オブジェクトとは(JavaScript) - やさしく つよく おもしろく

オブジェクトとは、「物体をデータ(プロパティ)と操作(メソッド)の集合として定義し、プログラムで扱えるようにしたもの」です。
イメージとして、車を物体(オブジェクト)とした場合、以下のようになります。

f:id:jsstudy:20170707210755p:plain

 

【JavaScript】オブジェクトとは - みこむらめもむらむらむら

JavaScriptのオブジェクトは
名前をキーにアクセスできる配列、要は連想配列である

 

  • JavaScriptの「オブジェクト」は、データ構造の一種で、ぶっちゃけ「連想配列」(ハッシュ)のこと。
  • 「キー」と「値」のペア(スロット)を、たくさん格納できる箱。
  • 値として、データのみならず、関数も格納できる。
  • ただの「連想配列」との違いは、「プロトタイプチェーン」という特別な機能が付いており、便利な操作ができる仕組みになっている点。

 

JavaScriptの「オブジェクト」は、「連想配列」+αという理解で、勉強を進めてみたいと思いますw

 

オブジェクトの初期化方法

JavaScriptで「オブジェクト」を用意する方法(初期化)は何通りかあり、必要に応じて使い分けることができます。

 

オブジェクト初期化子 - JavaScript | MDN

オブジェクトは

  1. new Object()、
  2. Object.create()、
  3. リテラル表記法 (initializer 表記法)

を使用して初期化されます。

 

基本的なオブジェクトを3通りの方法で作ってみます。

// (1) new Object()
var obj1 = new Object();
obj1.x = 1;
console.log(obj1);
console.log(typeof obj1);

// (2) Object.create()
var obj2 = Object.create(Object);
obj2.y = 2;
console.log(obj2);
console.log(typeof obj2);

// (3) リテラル表記法 (initializer 表記法)
var obj3 = {};
obj3.z = 3;
console.log(obj3);
console.log(typeof obj3);

 

  • (1)は、Javaのように、クラスベースのOOPっぽく書く場合、
  • (2)は、Ioのように、プロトタイプベースのOOPっぽく書く場合(クローンメソッド?)、
  • (3)は、連想配列っぽく書く場合、

というかんじでしょうか?

 

上記のコードを、Visual Studio Code+Node.jsで実行すると、以下の結果が出ました。

{ x: 1 }
object
{ y: 2 }
object
{ z: 3 }
object

 

どの書き方でもオブジェクト(連想配列)が作られて、スロット(キーと値のペア)を追加できました。

オブジェクトを単純に連想配列として使うだけなら、(3)オブジェクトのリテラル(書式)である「{}」で書くのが一番楽ですね?

 

 

「開眼!JavaScript」には、サンプルコードとその解説が掲載されています。

オブジェクトの生成について、順に見ていきます。

 

オブジェクトにプロパティを追加

(p.2)

次の一文を心に刻み込んでください。
「オブジェクトとは、名前と値を持つプロパティを格納するコンテナにすぎない。」
このコンテナの考え方は、JavaScriptの値を表現するための基礎です。

 

コンテナ=物を詰め込んでおく「箱」ですね?

 

http://jsfiddle.net/jseja/DD9k7/

// codyオブジェクトを生成
var cody = new Object();

// codyオブジェクトにプロパティを格納する(ここではドット表記法を使用)
cody.living = true;
cody.age = 33;
cody.gender = 'male';

console.log(cody); // 出力:Object {living: true, age: 33, gender: "male"}

 

Visual Studio Code+Node.jsで実行すると、以下の結果が出ました。

{ living: true, age: 33, gender: 'male' }

オブジェクトの基本な機能は、普通の連想配列ですね!

 

オブジェクトにメソッドを追加

(p.3)

メソッドをJavaScriptで実装すると以下のようになります。

 

http://jsfiddle.net/jseja/UwnX7/

var cody = new Object();
cody.living = true;
cody.age = 33;
cody.gender = 'male';
cody.getGender = function(){
    return cody.gender;
};
console.log(cody.getGender()); // 出力:male

 

Visual Studio Code+Node.jsで実行すると、以下の結果が出ました。

male

プロパティに入れられた「関数」は、「メソッド」という名前が付けられています。

 

Stringオブジェクトの生成

(p.4)

重要なのは、JavaScriptオブジェクトで値を表現するということを理解することです。

 

http://jsfiddle.net/jseja/n8RNk/

var myObject = new Object(); // Object()オブジェクトを生成

// ブラケット記法(2.3参照)でmyObjectの0、1、2の各プロパティに文字を代入
myObject['0'] = 'f';
myObject['1'] = 'o';
myObject['2'] = 'o';
console.log(myObject); // 出力:Object { 0="f", 1="o", 2="o"}

var myString = new String('foo'); // String()オブジェクトを生成(通常この方法では文字列を生成することはない)
console.log(myString); // 出力:foo { 0="f", 1="o", 2="o"}

 

Visual Studio Code+Node.jsで実行すると、以下の結果が出ました。

{ '0': 'f', '1': 'o', '2': 'o' }
[String: 'foo']

 

myStringが予想した結果と違ってたので、Chromeでも確かめてみます。

<!DOCTYPE html><html><body><script>

var myObject = new Object(); // Object()オブジェクトを生成

// ブラケット記法(2.3参照)でmyObjectの0、1、2の各プロパティに文字を代入
myObject['0'] = 'f';
myObject['1'] = 'o';
myObject['2'] = 'o';
console.log(myObject); // 出力:Object { 0="f", 1="o", 2="o"}

var myString = new String('foo'); // String()オブジェクトを生成(通常この方法では文字列を生成することはない)
console.log(myString); // 出力:foo { 0="f", 1="o", 2="o"}

</script></body></html>

 

上記のHTMLファイルをChromeで開き、コンソール画面で見ると、以下の結果でした。

f:id:jsstudy:20170708134111p:plain

 

確かにmyStringもオブジェクトになってますね!

 

[NOTE]

JavaScriptでは通常、文字列はプリミティブ型で表現し(例:var myString = 'foo';)、文字列オブジェクトを生成することはありません。

そのため、本節の例のように文字列'foo'がオブジェクト型として格納されていることが変に感じられるかもしれません。

ここであえてStringオブジェクトを例に出した理由は、JavaScriptでは通常オブジェクトではないと思われているもの(文字列、数値、真偽値)も含め、すべての値がオブジェクトとなりうるということを強調するためです。

 

なんで、こんな不自然な書き方が紹介されてるかというと、

「数値、文字列、真偽値などの基本型(プリミティブ型)の値も、JavaScriptの中では、オブジェクトとして操作できるようになっている。」

ということを実感しておいて欲しいからみたいです。

 

→ 後で出てくる「ラッパーオブジェクト」という仕組みの布石でしょうか?

 

コンストラクタ関数とは?

本書で頻繁に出てくる用語「コンストラクタ関数」の意味を確認しておきます。

(英単語の「constructor」は、「建設者」「建設会社」という意味)

コンストラクタ関数は、単に「コンストラクタ」とも呼びます。

 

JavaScriptOOPはクラスベースのOOPとは違うので、Javaなどのコンストラクタを思い浮かべたら戸惑うかも?

(他言語のコンストラクタの仕組みは、いったん忘れておきましょうw)

 

コンストラクタ - JavaScript 入門

コンストラクタは、オブジェクトを作成し、初期化する関数オブジェクト (Function オブジェクト) です。

 

JavaScriptのクラス?コンストラクタ?? - Qiita

JavaScriptにはクラスはありません。

コンストラクタからインスタンスを生成します。

 

  • Java等、クラスベースのOOPでは、「クラス」からインスタンス(個別のオブジェクト)を生成します。
  • JavaScriptには、「クラス」がないので、クラスからインスタンスを生成しません。ES6から用意された「class」は糖衣構文であり、内部的には従来と同じ挙動)
  • JavaScriptでは、(クラスの代わりに)「コンストラクタ関数」からインスタンス(個別のオブジェクト)を生成します。(こういう言い方で良いのかな?)
  • JavaScriptのコンストラクタ関数は、名前に「関数」と付いている通り、中身は関数であり、その実体はFunctionオブジェクトとのこと。

 

Java等、クラスベースの言語と比較するなら、

  • Java → 「クラス」からオブジェクトを作成する。
  • JavaScript → 「コンストラクタ関数」からオブジェクトを作成する。

という違いになるでしょうか。

 

var myObject = new Object()

というコード片では、「Object()」という部分が、「コンストラクタ関数」ですね。

=「Object」の後ろに「()」が付いているところが、関数の書式になってます。

 

コンストラクタ関数が他の関数と違うところは、コンストラクタ関数を使うと、「プロトタイプ」という特別な情報を自動的にくっつける点です。

JavaScriptのコンストラクタ関数、プロトタイプという仕組みは、別の機会に詳しく見てみます。)

 

コンストラクタ関数の作り方

JavaScriptのコンストラクタ関数は、JavaScriptで元々用意してくれているネイティブコンストラクタ関数だけでなく、ユーザーが自分でコンストラクタ関数を作って使うこともできます。

 

(p.5)

次の例では、人を表すオブジェクトを生成できるよう、Person()というコンストラクタ関数を定義します。

 

http://jsfiddle.net/jseja/m6nCr/

// 後でPerson()オブジェクトを生成するために、Personコンストラクタ関数を定義
var Person = function(living, age, gender) {
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

// Personオブジェクトをインスタンス化し、cody変数に格納する
var cody = new Person(true, 33, 'male');

console.log(cody);

/* JavaScript言語であらかじめ定義されているString()コンストラクタ関数も上記と同様のオブジェクトの生成パターンを持っています。
String()の場合コンストラクタ関数はJavaScriptにビルトインされているため、インスタンス化を行うだけで文字列インスタンスを得ることができます。
しかし組み込みのコンストラクタ関数を使おうが、Person()のようなカスタムコンストラクタ関数を使おうが、オブジェクトの生成パターンは同じです。 */
// 文字列オブジェクトをインスタンス化し、myString変数に格納 var myString = new String('foo'); console.log(myString);

 

Visual Studio Code+Node.jsで実行すると、以下の結果が出ました。

{ living: true, age: 33, gender: 'male', getGender: [Function] }
[String: 'foo']

 

ここで重要なのは、Object()コンストラクタ関数と先ほどの例のPerson()コンストラクタ関数はまったく同じ結果を出すことです。

両方とも同じプロパティとメソッドを持った同じオブジェクトを生成することができます。

 

上記のサンプルコードから、コンストラクタ関数の作り方と動作について、

  • 「Person」という名前の変数に、関数を定義する。
  • 「Person()」という関数は、コンストラクタ関数(オブジェクトのひな形)として使える。
  • new演算子とコンストラクタ関数を一緒に使うと、オブジェクトが作れる。(上記の例では、new Person()と書いて、codyというオブジェクトを作成)
  • ユーザーが自作したコンストラクタ関数(例:Person())は、JavaScriptで元々用意されているネイティブコンストラクタ関数(例:Object()、String()など)と同様に動作する。

ということが分かりました。

 

自作コンストラクタ関数の使いどころ

(p.6)

次の例ではcodyAとcodyBを生成しますが、それらは違う方法で生成されたにも関わらず、同じ値を持っています。

http://jsfiddle.net/jseja/qPTk9/

// Object()コンストラクタを使ってcodyAを生成

var codyA = new Object();
codyA.living = true;
codyA.age = 33; 
codyA.gender = 'male';
codyA.getGender = function() {
    return codyA.gender;
};

console.log(codyA); // 出力:Object {living: true, age: 33, gender: "male", getGender: function}

/* 次の例では、上の例と同じオブジェクトを生成しますが、次はObject()コンストラクタで一度きりのcodyを生成するのではなく、最初にcodyオブジェクト(もしくは他のPersonオブジェクト)を生成するPerson()コンストラクタを定義しnewを使ってインスタンス化します。 */

var Person = function(living, age, gender) {
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() {return this.gender;};
};

var codyB = new Person(true, 33, 'male');

console.log(codyB); // 出力:Object {living: true, age: 33, gender: "male", getGender: function}

 

Visual Studio Code+Node.jsで実行すると、以下の結果が出ました。

{ living: true, age: 33, gender: 'male', getGender: [Function] }
{ living: true, age: 33, gender: 'male', getGender: [Function] }

 

codyAとcodyBの主な違いはオブジェクト自体にあるのではなく、オブジェクトを生成するコンストラクタ関数にあります。

codyAオブジェクトはObject()コンストラクタを使って生成されました。

codyBを生成したPerson()コンストラクタは、単にcodyBを生成するだけではなく、「オブジェクトファクトリー」として多くのPerson()オブジェクトを生成することができます。

 

  • 単なるデータの入れ物=連想配列としてオブジェクトを使うだけなら、上記codyAのように、単発のオブジェクトでOK。
  • 同じオブジェクトをたくさん作りたい場合は、上記codyBのように、まずコンストラクタ関数を作成して、そのコンストラクタ関数からオブジェクトを作ればOK

 

JavaScriptの特徴

(p.7)

JavaScriptは、少数のネイティブオブジェクトコンストラクタが組み込まれた言語にすぎません。

この少数のネイティブコンストラクタが、数値、文字列、関数、オブジェクト、配列などの特化した型を表現するビルトインのオブジェクトを生成し、ユーザ定義オブジェクトコンストラクタ(Person()など)を構築するための材料を提供します。

JavaScriptはこのような構造を持つため、オブジェクトの生成パターンに関わらず、一般的に(プリミティブ型ではなく)オブジェクトが生成されます。

 

これ以降、本書ではオブジェクトやプリミティブ値の生成、性質、そして使い方の理解が焦点になります。

 

  • JavaScriptの内部は、シンプルな仕組みで出来ており、そこから他の様々な機能が作られている。
  • JavaScriptの特徴は、オブジェクトの作り方・使い方が分かれば、理解しやすい?

 

まとめ

  • JavaScriptの「オブジェクト」は、「連想配列」(ハッシュ)+α。
  • 単なる連想配列と違う点は、「プロトタイプ」という特別な情報も隠し持っている点。
  • この「プロトタイプ」を通じて、いろんな便利な操作ができる仕組みになってる。
  • オブジェクトの作り方(書式)は、3通りある。
    1. コンストラクタ関数 → 例:new Object()
    2. createメソッド   → 例:Object.create()
    3. リテラル表記法   → 例:{}
  • コンストラクタ関数は、オブジェクトを作るための関数で、自分でも作れる。
  • コンストラクタ関数は、「関数」という名前が付いている通り、中身は関数である。

 

実際にサンプルコードを動かしてみることで、JavaScriptのオブジェクトの作り方について理解できました。

次は、オブジェクトにくっついている「プロトタイプ」という情報ついて学んでみたいと思います。

 

 

開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質