以下はプロトタイプ的継承だけで一通りの機能を実現できる、という一つの例です。もちろん他にも書き方はありますし、newを使うのがよくないと主張しているわけではないです。
(誤解を生みそうな文体が混じっているようなので追記: 2011/5/14)
春ですし、少し初心者向けの記事を書きます。タイトル通り、JavaScriptのオブジェクト指向について。ちょっと長くなるので目次です。
JavaScript標準のオブジェクト指向といえばnewやらprototypeやらを書く必要がありますが、これらは書くのが面倒臭い上に気をつけないといけない点がたくさんあります。#"more">
クラスと書きましたが、JavaScriptにクラスはありません。この言葉は何度言っても言いすぎではないほどに重要です。もしJavaScriptの本で補足も何もなく「クラスを作ろう!」みたいなことが書いてあったら、それはJavaScriptを理解していない人が書いた本です。とっととゴミ箱へダンクしましょう。
JavaScriptにはオブジェクトと呼ばれる機構しか存在しないです。そして、どのオブジェクトも「クラス」のように扱うことができます。なぜならオブジェクトの方がクラスより汎用性の高い概念だからです。
「このオブジェクトをクラスとして使う」と取り決めれば、もうそれがクラスです。クラスは名前をUpperCamelCaseにするのが慣例ですね。
// Animalクラスvar Animal = { // member name: "動物" // method, breathe: function(){ alert("すーはー"); }, sayName: function(){ //メソッド内ではthisがオブジェクト自身を指す alert(this.name); }};JavaScriptではクラスがないので、クラスからインスタンスを作ることはできません。オブジェクトからオブジェクトを作ります。冒頭のobject関数はこれを簡単に行うための関数です。
var a = object(Animal);a.name; //"動物"a.breathe(); //"すーはー"がalertされる
単純にオブジェクトをコピーしてしまうと、メソッドや定数などの共有可能なものまでコピーすることになり無駄なメモリ消費が発生します。しかしobject関数はJavaScriptのプロトタイプ機構を使ってオブジェクトを作るため、効率がよくなります。
他の言語では「あるクラスを継承して別のクラスを作る」ということができますが、JavaScriptでは先述の「インスタンス化」と全く同じ操作で単一継承が実現できます。
var Dog = object(Animal); //これで継承が完了Dog.name = "犬"; //上書きできるDog.bowwow = function(){ alert("わんわん!") }; //追加できる//---こう書いても同じ-----------var Dog = object(Animal, { name: "犬", bowwow: function(){ alert("わんわん!") }});ここで作ったDogはAnimalを継承した状態になっています。
// 1. AnimalとDogは別々のオブジェクトです。alert(Animal === Dog); // false// 2. DogはAnimalのメンバーを全て持っています。Dog.breathe(); // "すーはー"// 3. Dogはメンバーを変更することができます。// 変更した内容はAnimalに影響を与えません。Dog.breathe = function(){ alert("くーん"); };Dog.breathe(); // "くーん"Animal.breathe(); // "すーはー"// 4. Animalを変更すると、Dogも影響を受けます。Animal.eat = function(){ alert("もぐもぐ") }; //Animalに追加したDog.eat(); //Dogにもeatが追加されているので、"もぐもぐ" がalertされるAnimal.breathe = function(){ alert("すーはーすーはー") };Dog.breathe(); // "くーん" // Dog側ですでに上書きしているので、// Animal側を書き換えても影響を受けない// 5. Dog側で行った変更をdeleteすると、Animalの内容に戻りますdelete Dog.breathe;Dog.breathe(); // "すーはーすーはー"もちろんDogもobject関数を使ってインスタンス化するように使えます。
var d = object(Dog);
正確に言うと、JavaScriptは多重継承をサポートしていません。しかし、関数をコピーすることができるので、多重継承のようなものを実現できます。ただし、JavaやPHPが実装していないことにも見られるように、多重継承は色々と問題があります。考えなしに使うのではなく、Mix-In的に使うのがよい作法です。ここでは詳細は割愛します。
// Wingクラスvar Wing = { fly: function(){ alert("ぱたぱた"); }};// Animalを単一継承し、WingをmixinしてBirdクラスを作るvar Bird = object(Animal, Wing, { name: "鳥"});// Animalを単一継承し、WingをmixinしてBatクラスを作るvar Bat = object(Animal, Wing, { name: "こうもり"});object関数は第一引数を継承のベースとして使い、そのあとの引数は出来上がった新しいオブジェクトへコピー(mixin)されます。引数は可変長であり、あとに書いた方が優先(上書き)されます。
少し長くなってきたので記事を分割して、残りは次回にします。
つづきはこちら。
[newを封印して、JavaScriptでオブジェクト指向する(2)]
冒頭のobject関数はプロトタイプ的継承という名前で知られているものを少し改良したものです。おそらくオリジナルはCrockford卿のこの記事です。
Prototypal Inheritance in JavaScript
この広告は90日以上新しい記事の投稿がないブログに表示されております。