タイトル
オブジェクト指向JavaScript
著者
Stoyan Stefanov (著), 水野貴明 (翻訳), 渋川よしき (翻訳)
出版社
アスキー・メディアワークス
Amazonで購入する

本書は、JavaScript を理解するためのものです。JavaScript はプロトタイプベースの言語で、クラスがなかったり、プロパティのアクセス修飾子がなかったり、継承の仕方が特別だったりします。

JavaScript を理解するには、JavaScript は全てがオブジェクトであることを覚えておく必要があります。本書は、こう言った、JavaScript が他のオブジェクト指向言語と違う点を整理し、JavaScript ではこう書くというのを丁寧に解説してくれています。

「JavaScript はブラウザ上で動く小さな言語」という認識だった昔とは、昨今では JavaScript の扱いは変わりました。サーバサイドでも JavaScript を動かしたり、スマートフォンの開発に JavaScript を使ったりと、JavaScript が使える舞台は広がっています。

JavaScript をもう一度ちゃんと理解したいという人に、本書はおすすめです。

おぼえがき

プリミティブデータ型

Number
1, 100, 3.14 などの数値。浮動小数点を含む。
String
‘hoge’, "foo bar", などで表現される文字列。
Boolean
true と false。
undefined
まだ存在していない変数にアクセスすると得られる値。
null
値がないことを表す値。

変数の型をしる typeof 演算子

変数や値の型を調べるときに使える typeof演算子は、"number""string""boolean""undefined""object""function" のいずれかの値(文字列)を返す。

Infinity(無限)

Infinity は JavaScript で扱えない大きな数値を表すのにつかう値。JavaScript で扱える最大の数値は 1.7976931348623157e+308、最小は 5e-324である。

1
2
3
4
5
6
>>> Infinity
Infinity
>>> typeof Infinity
"number"
>>> 1e309
Infinity

Boolean に変換されると false になる値

  • 空文字列""
  • null
  • undefined
  • 数値の 0
  • 数値の NaN
  • Boolean型の false

型変換の Tips

数字のような文字列を数値に変換する方法は parseInt() 関数を使う方法の他に、1 を掛けるという方法もある。

1
2
3
4
>>> var s = "100";
>>> s = s * 1;
>>> typeof s;
"number"

文字列に変換する場合、空文字と結合する方法がある。

1
2
3
4
>>> var n = 10;
>>> n = "" + n;
>>> typeof n;
"string"

配列の要素の削除

配列の要素の削除には delete 演算子を使うが、この演算子は配列の要素を減らすわけではなく、undefined を設定する。

1
2
3
4
5
6
7
>>> var a = [1, 2, 3];
>>> delete a[1];
true
>>> a.length;
3
>>> a;
[1, undefined, 3]

変数が定義されていて、値が割り当てられているかどうかを確認する方法

1
2
3
if (typeof something !== "undefined") {
  // 何かの処理
}

自分自身を書き換える関数

自分自身を書き換える関数の仕組みは、初期化などの一度だけ行ないたい処理がある場合に使う。

1
2
3
4
5
6
7
8
9
10
var a = function() {
  function someSetup() {
    var setup = 'done';
  }
  function actualWork() {
    alert('Worky-worky');
  }
  someSetup();
  return actualWork;
}();

オブジェクト

オブジェクトリテラル表記

{} を使ってオブジェクトを定義することをオブジェクトリテラル表記を呼ぶ。

1
2
3
4
var hero = {
  breed: 'Turtle',
  occupation: 'Ninja'
};

オブジェクトのプロパティ名はクウォートしないのが推奨されている。ちなみに、連想配列(ハッシュ)のキーは文字列である。

コンストラクタ関数

関数を new してオブジェクトを作ることで、関数をコンストラクタとして利用することができる。

1
2
3
4
5
6
7
function Hero(name) {
  this.name = name;
}

>>> var h1 = new Hero('hamasyou');
>>> h1.name;
"hamasyou"

グローバル変数

JavaScript のプログラムは様々なホスト環境(たとえばブラウザ環境)で動作する。JavaScript のホスト環境はグローバルオブジェクトを提供していて、グローバル変数はグローバルオブジェクトのプロパティになる。

たとえば、ブラウザ環境では window というグローバルオブジェクトが提供されており、グローバル変数はすべて、window のプロパティになる。

コンストラクタ関数を定義したにもかかわらず、new でオブジェクトをつくらなかった場合、this はグローバルオブジェクトを指すことになる。

constructor プロパティ

オブジェクトが作成されると、constructor プロパティと呼ばれる特別なプロパティに、オブジェクトを作成したときに使われたコンストラクタ関数がセットされる。

1
2
>>> h1.constructor;
Hero(name)

instanceof 演算子

instanceof 演算子を使うと constructor プロパティが指定した関数かどうかを調べることができる。

1
2
>>> h1 instanceof Hero;
true

オブジェクトの比較

オブジェクト同士を比較すると、両方の変数が同じオブジェクトの参照の場合のみ true を返す。

プロトタイプ

- このプロパティは関数がコンストラクタのときのみ使われる
- この関数を使って作られたオブジェクトも、prototype プロパティを持ち、関数の prototype と同じオブジェクトを参照する。このオブジェクトのプロパティは自分のプロパティと同じように使える

prototype プロパティ

関数は、prototype と呼ばれるプロパティを保持している。初期値は空のオブジェクトになっている。

1
2
3
4
5
6
7
8
9
10
11
function multiply(a, b) {
  return a * b;
}
>>> multiply.constructor;
Function()

>>> typeof multiply.prototype;
"object"

>>> multiply.prototype;
multiply {}

prototype プロパティに設定されているオブジェクトには、プロパティとメソッドを追加していくことができる。このオブジェクトは、multiply 関数自身にはなんの影響も与えない。追加したプロパティとメソッドは、multiply をコンストラクタとして利用した場合にのみ使われる。

1
2
3
4
5
6
7
>>> multiply.prototype.name = 'hamasyou';
>>> multiply.name;
"multiply"

>>> var hoge = new multiply();
>>> hoge.name;
"hamasyou"

prototype プロパティをいつ変更しても、すべてのオブジェクトが影響を受ける点は注意が必要。

prototype オブジェクトのプロパティを上書きする

オブジェクト自身のプロパティの方が、prototype オブジェクトのプロパティよりも優先して解決される。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var Salary = (function() {
  var salary = function() {};
  salary.prototype.base = 50000;
  salary.prototype.total = function() {
    return this.base * 1.05;
  };
  return salary;
})();

>>> var hoge_salary = new Salary();
>>> hoge_salary.base = 20000;
>>> hoge_salary.total();
21000

var hama_salary = new Salary();
>>> hama_salary.total();
52500

継承

プロトタイプチェーンで継承を実現する

JavaScript の prototype プロパティはオブジェクトであるので、自身の prototype も持っている。このように prototype をチェーンして辿っていくことで、継承を実現することができる。

次の例は、本書 P.183 のプロトタイプチェーンの例である。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function Shape() {
  this.name = 'shape';
  this.toString = function() { return this.name; }
}

function TwoDShape() {
  this.name = '2D shape';
}

function Triangle(side, height) {
  this.name = 'Triangle';
  this.side = side;
  this.height = height;
  this.getArea = function() {
    return this.side * this.height / 2;
  };
}

TwoDShape.prototype = new Shape();
Triangle.prototype = new TwoDShape();
TwoDShape.prototype.constructor = TwoDShape;
Triangle.prototype.constructor = Triangle;

>>> var my = new Triangle(5, 10);
>>> my.getArea();
25
>>> my.toString();
"Triangle"

Triangle クラスには toString メソッドは定義されていないが、Shape 関数で定義されていることで、プロトタイプチェーンをたどって呼び出すことができる。

継承を行った後は、constructor を再設定しておくとよい。