- 追加された行はこの色です。
- 削除された行はこの色です。
* クラス(オブジェクト)の作り方 [#ee1faea0]
* 関数オブジェクトを使ったクラス作成 - 応用 [#ee1faea0]
** オブジェクトを生成 [#mc80828f]
var obj = new Object();
obj.name = 'taro';
obj.say = function () { alert("hello, " + this.name); };
を省略して、オブジェクトリテラルで書くと、
var obj = { name : "taro",
say : function() { alert("hello, " + this.name); }
};
** クラスの作成 [#u48ec2eb]
** クラスを定義 [#u48ec2eb]
*** 空のコンストラクタ [#ga5b2288]
var Person = function() {};
*** コンストラクタでメソッドやフィールドを定義[#fc448499]
thisを使ってクラスのプロパティにアクセスする。
var Person = function(name) {
*** 1. 空のコンストラクタ [#ga5b2288]
var Animal = function() {};
- 関数オブジェクトをクラスのコンストラクタに見立てる。
*** 2. コンストラクタでメソッドやフィールドを定義[#fc448499]
var Animal = function(name, age) {
this.name = name;
this.say = function() { alert("hello, " + this.name); };
this.age = age;
this.sayName = function() {
alert("My name is " + this.name);
};
};
ただし、この方法はインスタンス生成ごとにメソッドを定義する事になり、メモリ効率が悪い。これを避けるには、プロトタイプによるメソッドやフィールドを定義を行う。
** クラスからインスタンスを生成 [#m5dce2e9]
var person = new Person("taro");
person.say();
- thisを使ってクラスのプロパティにアクセスする。
- ただし、この方法はインスタンス生成ごとにメソッドを定義する事になり、メモリ効率が悪い。これを避けるには、↓のようにプロトタイプによるメソッドの定義を行う。
** クラスにプロトタイプでメソッドやフィールドを定義[#n7668f55]
Person.prototype = {
say2: function() {
alert("hello2, " + this.name);
*** 3. プロトタイプでメソッドを定義[#n7668f55]
var Animal = function(name, age) {
this.name = name;
this.age = age;
};
Animal.prototype = {
sayName: function() {
alert("My name is " + this.name);
}
};
person.say2();
*** プロトタイプ汚染 [#pc7c1759]
この方法でArrayのような組込みクラスを拡張する事が可能だが、安易に拡張するとfor inでオブジェクトのプロパティを列挙すると拡張したプロパティ(メソッド)と元のプロパティ(メソッド)が混ざってしまう(プロトタイプ汚染)ので注意が必要。
:プロトタイプ汚染について|この方法でArrayのような組込みクラスを拡張する事が可能だが、安易に拡張するとfor inでオブジェクトのプロパティを列挙すると拡張したプロパティ(メソッド)と元のプロパティ(メソッド)が混ざってしまう(プロトタイプ汚染)ので注意が必要。
** クラスの継承 [#w1db1e89]
***親クラス作成 [#ac0cfa4d]
var Person = function(name) { this.name = name; };
Person.prototype = { say: function() { alert("hello, " + this.name) } };
*** 子クラス作成 [#q7f19729]
var Man = function(name) { this.name = "Mr." + name; };
***親クラスを継承 [#ae15c212]
Man.prototype = new Person;
var m = new Man("taro");
m.say();
*** 4. プロパティもプロトタイプに乗せたい場合 [#zca9d352]
var Animal = function(name, age) {
this.init.apply(this, arguments);
};
Animal.prototype.init = function (name, age) {
this.name = name;
this.age = age;
sayName: function() {
alert("My name is " + this.name);
}
};
*** プロトタイプチェイン [#efb4d835]
メソッドの検索は次の順で行われる。
- m.say()
- Man.prototype.say()
- Person.prototype.say()
- Object.prototype.say()
- 初期化メソッド(ここではinit())を作って、コンストラクタではそれをapply()で呼ぶだけにする。
- apply()とは [[JavaScript/文法/関数/call()とapply()]]。
親クラスを辿って行き、最終的にObject.prototypeで見つからなければ、終了する。
** インスタンスを生成・メソッドを利用 [#m5dce2e9]
var a = new Animal("Taro", 10);
a.sayName();
*** プロトタイプ継承の注意点 [#fbdffe52]
なお、継承のために、
Man.prototype = new Person;
ではなく、
Man.prototype = Peroson.prototype;
としてはならない。この場合、ManのprototypeはPersonのprototypeを参照する事になるので、
Man.prototype.say2 = function () { alert('hello2') };
のようにManにメソッドを追加すると、Personにもメソッドが追加されてしまう。
var p = new Person();
p.say2(); // 本来、未定義であるべき
** 継承 [#w9c0d0c2]
*** 子クラスの作成 1 [#z6e09049]
var Dog = function(name, age) {
this.name = name;
this.age = age;
};
Dog.prototype = new Animal;
Dog.prototype.sayAge = function() {
alert("My age is " + this.age);
}
** JavaScriptのクラス(オブジェクト)の問題点 [#e4ecfe17]
- 親クラスのコンストラクタ(メソッド)を呼び出すのが難しい。
- 多重継承が難しい。
これらを解決するには、何らかのライブラリを使うのが妥当。
- Dog.prototype = new Animal で継承を実現している。
- Dog.prototype.sayAge = function()... でメソッドを子クラスに追加している。
** Prototype.jsを使って継承 [#q91482f9]
var Woman = Class.create(); // クラス定義
Object.extend(Woman.prototype, Person.prototype); // 継承
Object.extend(Woman.prototype,{ // メソッドのオーバーライド
initialize: function(name) {
this.name = "Miss." + name;
}
});
var w = new Woman("hanako");
w.say();
*** 子クラスのインスタンスを作成・メソッドを利用 [#ccee7581]
var d = new Dog("Jiro", 5);
d.sayAge();
*** 子クラスの作成 2(子クラスのコンストラクタで親クラスのコンストラクタを利用) [#fe78ad54]
var Dog = function(name, age) {
Animal.call(this, name, age);
};
Dog.prototype = new Animal;
Dog.prototype.sayAge = function() {
alert("My age is " + this.age);
}
- 子クラスの作成 1ではコンストラクタ内での処理を書き直す必要があるので、call()を使って、子クラスthisに親クラスのコンストラクタメソッドAnimal()を適用して、書き直す手間を省く。
- call()とは [[JavaScript/文法/関数/call()とapply()]]。
*** prototypeのconstructorプロパティ [#y0fa63a1]
↑のままではDogクラスのprototypeのconstructorプロパティはAnimalなので、これをDogにする場合は↓のようにする。
Dog.prototype = new Animal;
Dog.prototype.constructor = Dog;