JavaScript文法(7) オブジェクトの基礎

# この記事の内容

* オブジェクトのプロパティやメソッドを定義する方法
* 他のオブジェクトのメソッドを借りる方法

# 目次

(1) [学習環境の構築と基本的な書き方](http://qiita.com/azk0305/items/a13d494178d83fc8f2bc)
(2) [変数とデータ型](http://qiita.com/azk0305/items/d78d744dff9656b22dd0)
(3) [演算子および配列](http://qiita.com/azk0305/items/748f4afadcfa5350a552)
(4) [制御構文と関数](http://qiita.com/azk0305/items/ed943040a8f7140d5a48)
(5) [関数の応用1](http://qiita.com/azk0305/items/f7e0653b20425fdb9f1b)
(6) [関数の応用2](http://qiita.com/azk0305/items/0fd54f9c66f726443dd6)
(7) オブジェクトの基礎 **<-- この記事の内容**
(8) [JavaScriptのオブジェクト指向プログラミング1 概要](http://qiita.com/azk0305/items/1e1bd10522927eaddd6a)
(9) [JavaScriptのオブジェクト指向プログラミング2 オブジェクトの作り方と継承](http://qiita.com/azk0305/items/386b3a2ac41caf3101e1)
(10) [JavaScriptのオブジェクト指向プログラミング3 多態性](http://qiita.com/azk0305/items/1c713562f6f842dcf1dc)
(11) [JavaScriptのオブジェクト指向プログラミング4 カプセル化](http://qiita.com/azk0305/items/914f6e447b41d4ced25e)
(12) [ES6の新機能について](http://qiita.com/azk0305/items/ebfb43c088101f7138f9)

# JavaScriptで扱うデータは、すべてオブジェクトである

ここまで観てきたように、配列は `Array` 型のオブジェクト、連想配列は `Object` 型のオブジェクト、関数は `Function` 型のオブジェクトになる。他にも、文字列データは `String` 型のデータであり、数値データは `Number` 型のデータになる。
つまり、JavaScriptで扱うデータは、ほぼすべてがオブジェクトであると言える（nullやundefinedなど一部の型は除く）。

オブジェクトとはどういう性質をもったものであるかを改めておさらいすると、以下のとおり。

* 属性（プロパティ）を持つ
* 振る舞い（メソッド）を持つ
* 全く同じオブジェクトを2つ以上つくれない（各オブジェクトは唯一無二の存在である）
* ひとつのオブジェクトは、他のオブジェクトと関連性を持てる

# JavaScriptのオブジェクトのプロパティ・メソッド

プロパティについては以前、連想配列のところで使い方を観てきた。

```js:bs07_01.js
var student = {
  name: "太郎",
  age:  25
};

console.log(student.name);    // 太郎 と表示される
```

連想配列のキーがオブジェクトのプロパティ名、値はプロパティに指定されたデータとなる。

では、メソッドをどのように定義すれば良いか。それは、匿名関数を使って関数を変数に代入した書き方と同じ感覚で、プロパティ名に関数の定義を紐づけする。

```js:bs07_02.js
var student = {
  name:  "太郎",
  age:   25,
  greet: function() {
    console.log("今日は良い天気ですね");
  }
};

console.log(student.name);    // 太郎 と表示される
student.greet();              // 今日は良い天気ですね と表示される
```

上の例は、`greet` という名前のプロパティを追加し、その値として匿名関数の定義を代入している。このような定義をすれば、 `オブジェクトの変数名.関数名()` といった書き方で、定義した関数を実行できる。

# thisキーワード

オブジェクトのプロパティとして定義している関数の中で別のプロパティの値を参照したい場合は、`this` というキーワードを利用する。`this` は、自分自身を指し示すキーワードである。

```js:bs07_03.js
var student = {
  name:  "太郎",
  age:   25,
  greet: function() {
    console.log("今日は良い天気ですね");
  },
  introduce: function() {
    console.log("私の名前は" + this.name + "です");
  }
};

console.log(student.name);    // 太郎 と表示される
student.greet();              // 今日は良い天気ですね と表示される
student.introduce();          // 私の名前は太郎です と表示される
```

上の例は、さらに `introduce` というプロパティを追加し、「私の名前は○○です」と表示する内容の処理を定義している。このとき、○○の部分には、自身の `name` プロパティの中身を表示するようにしたいので、 `this.name` という書き方で名前を指定している。

# 別のオブジェクトのメソッドを使わせてもらう

student1という名前のオブジェクトと、student2という名前のオブジェクトがあるとする。student1のオブジェクトには `introduce` というメソッドが定義されているとする。student2でも `introduce` のメソッドを実装したいものの、内容はstudent1のそれと同じ内容にしたいとき、そっくりそのままstudent2に `introduce` メソッドを追記してしまうとコードの重複になり、お行儀が悪い。このとき、**student1のintroduceメソッドを使わせてもらう（メソッドを借りて、さも自分が持っているメソッドであるかのように実行する）**ことができる方法がある。

## callメソッド

`Function` 型のオブジェクトが持つメソッドのひとつに `call` というメソッドがある。これは、引数に指定したオブジェクトに、その関数自身を使っていいよと許可を出し（関数を貸してあげて）、すぐに実行するメソッドである。

```js:bs07_04.js
var student1 = {
  name:  "太郎",
  introduce: function() {
    console.log("私の名前は" + this.name + "です");
  }
};

var student2 = {
  name: "花子"
};

student1.introduce();    // 私の名前は太郎です と表示される

// introduceメソッドをstudent2に貸し出し、実行。
// 私の名前は花子です と表示される。
student1.introduce.call(student2);
```

`貸し出したいメソッドを持つオブジェクト.そのメソッド名.call(貸し出したい相手のオブジェクト名)` のように記述する。メソッドの引数を与えることも可能。callメソッドの2番目以降の引数に、データを `introduce` メソッドの引数の順番どおりに指定する。

```js:bs07_05.js
var student1 = {
  name:  "太郎",
  introduce: function(name, pref) {
    console.log("私の名前は" + this.name + "です");
    console.log(name + "歳です");
    console.log(pref + "在住です");
  }
};

var student2 = {
  name: "花子"
};

student1.introduce(25, "東京都"); 

// introduceメソッドをstudent2に貸し出し、実行。
student1.introduce.call(student2, 20, "埼玉県");
```

```text:bs07_05.jsの実行結果
私の名前は太郎です
25歳です
東京都在住です
私の名前は花子です
20歳です
埼玉県在住です
```

## applyメソッド

callメソッドとほぼ同じ使い方、かつ同じ処理内容をするメソッドとして `apply` メソッドがある。`call` との違いは、`introduce` メソッドへの引数の与え方を、配列にして第2引数に渡すという点。下記の例は、先ほどのものと実行結果が同じになる。

```js:bs07_05.js
var student1 = {
  name:  "太郎",
  introduce: function(name, pref) {
    console.log("私の名前は" + this.name + "です");
    console.log(name + "歳です");
    console.log(pref + "在住です");
  }
};

var student2 = {
  name: "花子"
};

student1.introduce(25, "東京都"); 

// introduceメソッドをstudent2に貸し出し、実行。
var opt = [20, "埼玉県"];
student1.introduce.apply(student2, opt);
```

※オブジェクトの定義について、もう少しオブジェクト指向プログラミングらしい書き方もできるが、それについては、後の記事にて。

# 次回予告
JavaScriptのオブジェクト指向プログラミングに関する概要