スタッフブログ
satoです。
JavaScriptのライブラリでお馴染みのものにPrototype(prototype.js)があります。
このライブラリは、早い段階からJavaScriptでクラス機構を実現するための仕組みが用意されていたのですが、あまり使い勝手がいいと言えるものではありませんでした。
一昨年くらいに1.6がリリースされて、クラス作成周りが一新されたのですが、あまり情報がない(というか、あるのですが古い情報が優先して検索される)ので、ここでも書いておこうと思います。
■クラス作成
・1.5以前
・1.6
Class.createの中に直接書けるようになりました。ちなみに1.5以前の書き方でも通るようになっていますが、この後の継承などで問題が出ると思うので、1.6の書き方を使うようにしましょう。
■継承
・1.5以前
・1.6
Object.extendを使わなくなったのが大きな違いです。
そもそもObject.extendの実装を見ると、
のように、プロパティをコピーしているだけで、継承と呼ぶには厳しい実装でした。どちらかといえばmixinに近い実装だと思います。
1.6の実装になって何が嬉しいかと言うと、
・書き方がわかりやすい
Object.extendを複数回呼ぶ必要もありませんし、明示的にprototypeを指定する必要もなくなりました。
・親クラスのメンバを呼べるようになった
恐らくこれが一番大きいです。
1.5では、
のような強引な手法を採るしかありませんでしたが、1.6では、
のように、第一引数を$superという名前にすると、そこに親クラスのメソッドが入るようになりました。
ちなみにこの場合、getNameに引数を渡して受け取る場合、第二引数以降に割り当てられます。
みたいな感じです。
■まとめ
そもそもクラスとか定義するのはJavaScriptっぽくない感じはするのですが、単純に慣れているというのと、可読性が向上するという意味で積極的に使うようにしています。
最近はjQuery派とフルスクラッチ派が強い印象がありますが、prototype.jsは基本機能が整っていて、今でも十分実用的に使えるライブラリだと思います。
JavaScriptのライブラリでお馴染みのものにPrototype(prototype.js)があります。
このライブラリは、早い段階からJavaScriptでクラス機構を実現するための仕組みが用意されていたのですが、あまり使い勝手がいいと言えるものではありませんでした。
一昨年くらいに1.6がリリースされて、クラス作成周りが一新されたのですが、あまり情報がない(というか、あるのですが古い情報が優先して検索される)ので、ここでも書いておこうと思います。
■クラス作成
・1.5以前
var Animal = Class.create();
Animal.prototype = {
initialize: function() {
this.name = 'Animal';
},
getName: function() {
return this.name;
}
};
alert(new Animal().getName()); // 'Animal'
・1.6
var Animal = Class.create({
initialize: function() {
this.name = 'Animal';
},
getName: function() {
return this.name;
}
});
alert(new Animal().getName()); // 'Animal'
Class.createの中に直接書けるようになりました。ちなみに1.5以前の書き方でも通るようになっていますが、この後の継承などで問題が出ると思うので、1.6の書き方を使うようにしましょう。
■継承
・1.5以前
var Animal = Class.create();
Animal.prototype = {
initialize: function() {
this.name = 'Animal';
},
getName: function() {
return this.name;
}
};
var Cat = Class.create();
Object.extend(Cat.prototype, Animal.prototype);
Object.extend(Cat.prototype, {
initialize: function() {
this.name = 'Cat';
}
});
alert(new Animal().getName()); // 'Animal'
alert(new Cat().getName()); // 'Cat'
・1.6
var Animal = Class.create({
initialize: function() {
this.name = 'Animal';
},
getName: function() {
return this.name;
}
});
var Cat = Class.create(Animal, {
initialize: function() {
this.name = 'Cat';
}
});
alert(new Animal().getName()); // 'Animal'
alert(new Cat().getName()); // 'Cat'
Object.extendを使わなくなったのが大きな違いです。
そもそもObject.extendの実装を見ると、
Object.extend = function(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
return destination;
}
のように、プロパティをコピーしているだけで、継承と呼ぶには厳しい実装でした。どちらかといえばmixinに近い実装だと思います。
1.6の実装になって何が嬉しいかと言うと、
・書き方がわかりやすい
Object.extendを複数回呼ぶ必要もありませんし、明示的にprototypeを指定する必要もなくなりました。
・親クラスのメンバを呼べるようになった
恐らくこれが一番大きいです。
1.5では、
var Cat = Class.create();
Object.extend(Cat.prototype, Animal.prototype);
Object.extend(Cat.prototype, {
initialize: function() {
this.name = 'Cat';
},
getName: function() {
return (Animal.prototype.getName.bind(this))() + 'だよ';
}
});
alert(new Animal().getName()); // 'Animal'
alert(new Cat().getName()); // 'Catだよ'
のような強引な手法を採るしかありませんでしたが、1.6では、
var Cat = Class.create(Animal, {
initialize: function() {
this.name = 'Cat';
},
getName: function($super) {
return $super() + 'だよ';
}
});
alert(new Animal().getName()); // 'Animal'
alert(new Cat().getName()); // 'Catだよ'
のように、第一引数を$superという名前にすると、そこに親クラスのメソッドが入るようになりました。
ちなみにこの場合、getNameに引数を渡して受け取る場合、第二引数以降に割り当てられます。
getName('hoge') → getName: function($super, hoge) {
みたいな感じです。
■まとめ
そもそもクラスとか定義するのはJavaScriptっぽくない感じはするのですが、単純に慣れているというのと、可読性が向上するという意味で積極的に使うようにしています。
最近はjQuery派とフルスクラッチ派が強い印象がありますが、prototype.jsは基本機能が整っていて、今でも十分実用的に使えるライブラリだと思います。