コンストラクタパターン: オブジェクトの作成

Last Change:21-May-2016.
Author:qh73xe
Reference:https://www.oreilly.co.jp/books/9784873116181/

ある程度オブジェクト指向の言語に慣れている人間にとって、 まずはクラスを作成できると安心だと思います。

ただし、 JS では厳密にはクラスの概念がありません。 そのため、クラスっぽいものを作成するには、 得的のオブジェクトを作成するコンストラクタを作成することが多いです。

  • このページでは ブラウザ上で JS を扱うのではなく、SpiderMonkey を利用して端末上で JS を操作しています。

オブジェクトの作成

というわけで、まずは、コンストラクタが作成をする対象のオブジェクトを手動で作成するところから始めます。 オブジェクトの作成方法は以下の二つがあります。

js> var hoge = {};
js> var foo = new Object()

個人的には後者の方法が好きです。 そう、この方法では Object コンストラクタを利用して foo というオブジェクトを作成していますから。 そういう意味で明示的な記述だと思います。

注釈

google の コーディングスタイル的には {} 表記がいいそうです。

値の割り当て

さてこの hoge とか foo はまだ何も情報をもっていません。 オブジェクトに キー と値を割り当てる方法には 4 つの方法があります。 ここでは先程作成したオブジェクト hoge に割り当てを行っていきます。

js> hoge.a = "hello";  // ドット記法
js> hoge["b"] = "Good Morning";  // 鉤括弧記法

値を参照するには以下のようにします。

js> hoge["a"];
js> hoge.b;
  • 一応、参照形式も記法は二つ自由に使用できることを明示しているつもりです。

上記二つは シンプルな方法です。 これとは別に defineProperty を使用することも可能です。

Reference:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
test_defineProperty.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var hoge = new Object();
Object.defineProperty(
    hoge,
    "a", {
        value: "hogehoge",
        writerable: true,
        enumerable: true,
        configurable: true
    }
);

print(hoge.a);

この記法はかなり明示的な方法だと思いますが、 少し面倒です。

省略系の記法として以下の方法があります。

test_defineProperty2.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var defineProp = function(obj, key, value){
    var config = {};
    config.value = value;
    Object.defineProperty(obj, key, config);
}

// 使うには
var person = Object.create(null);

// プロパティーでオブジェクトを追加
defineProp(person, "name", "Tanaka Taro");
defineProp(person, "dateOfBirth", "1981");

print(person.name);
print(person.dateOfBirth);

複数のプロパティをまとめて決定したい場合, defineProperties を使用します。

test_definePropertys.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
var person = new Object();
Object.defineProperties(
    person, {
      name: {
          value: "Tanaka Taro",
          writerable: true,
      },

      dateOfBirth: {
          value: "1981",
          writerable: true,
      }
    }
);

print(person.name);

継承

defineProperty を使用したオブジェクトの宣言は、 継承に利用することが可能です。

test_inheritance.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
var defineProp = function(obj, key, value){
    var config = {};
    config.value = value;
    Object.defineProperty(obj, key, config);
}

// 使うには
var person = Object.create(null);
// プロパティーでオブジェクトを追加
defineProp(person, "fname", "Tanaka");

var taro = Object.create(person)
var ziro = Object.create(person)
defineProp(taro, "forder", "1");
defineProp(ziro, "forder", "2");

print(taro.fname, taro.forder);
print(ziro.fname, ziro.forder);

基本的なコンストラクタ

先に述べたように、 JS にはクラスの概念が存在しません。 代わりにオブジェクトに働き掛ける特別なコンストラクタ関数を持っています。

test_constructor.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function Car(model, year, miles) {
  this.model = model;
  this.year = year;
  this.miles = miles;

  this.show = function(){
    return this.model + "has done " + this.miles + " miles";
  };
}

var civic = new Car("Honda Civic", 2009, 20000);
var mondeo = new Car("Ford Mondeo", 2010, 5000);

print(civic.show());
print(mondeo.show());

上記の例のように、 JS では特定の関数を使用する際に new をつけると、 その関数がコンストラクタとして機能します。

注釈

this

上記コードに含まれる this は大体 python の self と一緒です。

プロトタイプを使用したコンストラクタ

上記の例はシンプルではあっても、完全ではありません。

test_constructor.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function Car(model, year, miles) {
   ...
   this.show = function(){
     return this.model + "has done " + this.miles + " miles"
   }
}

var civic = new Car("Honda Civic", 2009, 20000);
var mondeo = new Car("Ford Mondeo", 2010, 5000);
...

上記の記法では関数 Car が呼び出されるたびに それぞれ新しい show 関数が作られることになります。 つまり、civic, mondeo でそれぞれ別の関数オブジェクトが生成されていることになります。 どの Car オブジェクトでも同じ関数なので、関数オブジェクトも1つのほうがよいはずです。

これを解決する方法として プロトタイプを利用する方法があります。

test_constructor2.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function Car(model, year, miles) {
  this.model = model;
  this.year = year;
  this.miles = miles;
}

Car.prototype.show = function(){
  return this.model + "has done " + this.miles + " miles";
};

var civic = new Car("Honda Civic", 2009, 20000);
var mondeo = new Car("Ford Mondeo", 2010, 5000);

print(civic.show());
print(mondeo.show());