Web技術勉強会 20111112
-
Upload
ryuichi-tanaka -
Category
Technology
-
view
735 -
download
2
description
Transcript of Web技術勉強会 20111112
プロトタイプベースOOP
ライブラリmix.jsライブラリmix.js
Web技術勉強会 2011/11/12
Ryuichi TANAKA(@mapserver2007)
mix.jsとは
• https://github.com/mapserver2007/mixjs
• プロトタイプベースオブジェクト指向プログラミングを支援するライブラリ
• 親子関係が持てる• 親子関係が持てる
• 簡単に継承(mix-in)できる
• IEでも動く
JavaScriptで継承はやりづらい
• 「JavaScript」「継承」とかで検索するとでてくるが、どれも微妙。
• A.prototype = new B();
–ありがち–ありがち
–そもそも親子関係になってない
• jQuery.extend
–プロパティを上書きするだけ
–やっぱり親子関係になってない
継承は親子を作る
• 継承というからには親子関係が普通ある
• JavaScriptはそれをやるのがすごく大変
とにかく簡単に継承
• var obj = A.mix(B)
• これだけで継承(mix-in)が完了
• とにかく簡単
バグは収束した
• mix.jsベースでコードを書き直し中
• 動作問題なし
• バグはほぼ潰しきった(はず)
機能を簡単に説明機能を簡単に説明
モジュールを定義する
• モジュールという単位でクラスに相当するものを定義する
• モジュールを組み合わせて一つのオブジェクト(インスタンスに相当)を作るト(インスタンスに相当)を作る
• mix-inした順番通りに親子関係が構築される
モジュールを定義する
Mixjs.module(“Iphone”, {
name: function() {
return “iPhone”;return “iPhone”;
}
});
// Iphone.name();
モジュールを定義する
var namespace = {}:
Mixjs.module(“Iphone”, namespace, {
name: function() {
return “iPhone”;return “iPhone”;
}
});
// namespace.Iphone.name();
モジュールをmix-inする
var obj = Iphone.mix(Feature);
var obj2 = Iphone.mix(Feature).mix(Telephone);
var obj3 = Iphone.mix(Feature, Telephone);
親にしかないメソッドにアクセス
var obj2 = Iphone.mix(Feature).mix(Telephone);
// Telephone#getType()にアクセスしたい
// Iphone, FeatureはgetType()を持っていない
obj2.getType(); // OKobj2.getType(); // これでOK
IE以外ではプロトタイプチェーンで取得、IEではmix-in時に親のメソッドを自身にコピーする
親にある同じ名前のメソッドにアクセスしたい
var obj2 = Iphone.mix(Feature).mix(Telephone);
// name()はIphone, Feature, Telephone全員が
// もっている
obj2.name(); // Iphone#name()obj2.name(); // Iphone#name()
obj2.parent.name(); // Feature#name()
obj2.parent.parent.name(); // Telephone#name()
あらかじめmix-in済みのモジュールを定義したい
• これまでのmix-inは外部mix-in
• 外部mix-inはモジュール定義後に動的にmix-
inする
• モジュール定義時に親子関係が確定してい• モジュール定義時に親子関係が確定している場合は静的にmix-inするほうが自然
静的にmix-in(内部mix-in)
Mixjs.module(“Iphone”, {
include: Feature,
name: function() {name: function() {
return “iPhone”;
}
});
静的にmix-in(内部多重継承)
Mixjs.module(“Iphone”, {
include: [Feature, Telephone],
name: function() {name: function() {
return “iPhone”;
}
});
mix-in済みモジュールか判定
var obj = Iphone.mix(Feature);
obj.has(Iphone); // true
obj.has(Telephone); //false
自分自身の参照位置を基底に移動
Mixjs.module(“Feature”, {
name: function() {
// this.name()だと参照できない// this.baseを使うと参照位置を継承済みオブジェクトの最も子供の// 位置に移動させることができるthis.base.name();
}}
});
Mixjs.module(“Iphone”, {
include: Feature,
name: function() {
return “iphone”;
}
});
Iphone.parent.name(); // iphone
同じモジュールはmix-inできない
• エラーにはならないが同じモジュールはmix-
inできない
var obj = Iphone.mix(Iphone);
obj.hasOwnProperty(“parent”); // falseobj.hasOwnProperty(“parent”); // false
継承のルール継承のルール
1.通常のmix-in
• M1 mix M2 M1 -> M2
• M1 mix M2 mix M3
M1 -> M2 -> M3M1 -> M2 -> M3
2.多重継承
• M1 mix (M2, M3)
M1 -> (M2->M3) # ()内でまずmix-in
M1 -> (M2’)M1 -> (M2’)
M1 -> M2-> M3通常のmix-inのチェーンとはmix-in順が異なる
3.同じモジュールをmix-in
• T1 mix T1 T1
3.同じモジュールをmix-in
• T1 mix T1 T1
• T1 mix T2 mix T1 T1 -> T2
4.mix-in済みモジュールをmix-in
• T1 mix (T2 mix T1) mix T1
T1 -> T2’ -> T1
T1 -> T2’T1 -> T2’
T1 -> T2 -> T1
T2’はT2ともT1とも等しくないためこのようにmix-inされる
5.同じmix-in済みモジュールが複数ある場合のmix-in
T1 mix (T2 mix T1) mix (T2 mix T1)
T1 -> T2’ -> T2’
T1 -> T2’T1 -> T2’
T1 -> T2 -> T1
T2’は2つあるので1つはmix-inされない
6.すべて異なるモジュールだが同じmix-in順序が含まれる
T1 mix (T3 mix T2 mix T1) mix (T2 mix T1)
T1 -> T3’ -> T2’
T1 -> T3->T2->T1->T2->T1T1 -> T3->T2->T1->T2->T1
Cyclic Error
T2->T1が繰り返されていると循環参照エラーとなる。
パフォーマンス測定パフォーマンス測定
前提条件
• 測定環境
– Core2Duo P8700 2.53GHz
– Mem 4GB
– WindowsVista Ultimate SP2– WindowsVista Ultimate SP2
• 実行環境
– Chrome15.0.874.106 m
– IE8
– Firefox8
測定ツール
• benchmark.js
– http://benchmarkjs.com/
• 実行プログラム
– https://gist.github.com/1358167– https://gist.github.com/1358167
測定結果
include: Test1
include: [Test1, Test2]
include: [Test1, Test2, Test3]
0 0.2 0.4 0.6 0.8 1 1.2
Test1.mix(Test2)
Test1.mix(Test2).mix(Test3)
Test1.mix(Test2, Test3, Test4)
(Test1.mix(Test2)).mix(Test3.mix(Test4))
IE8
Firefox
Chrome
Chrome
Pettern ops/sec msec
Test1.mix(Test2) 55,646 0.017971
Test1.mix(Test2).mix(Test3) 9,264 0.107945
Test1.mix(Test2, Test3, Test4) 13,588 0.073594Test1.mix(Test2, Test3, Test4) 13,588 0.073594
(Test1.mix(Test2)).mix(Test3.mix(Test4)) 13,639 0.073319
include: Test1 11,232 0.089031
include: [Test1, Test2] 3,750 0.266667
include: [Test1, Test2, Test3] 2,374 0.42123
IE8
Pettern ops/sec msec
Test1.mix(Test2) 7526 0.132873
Test1.mix(Test2).mix(Test3) 1739 0.575043
Test1.mix(Test2, Test3, Test4) 3244 0.308261Test1.mix(Test2, Test3, Test4) 3244 0.308261
(Test1.mix(Test2)).mix(Test3.mix(Test4)) 2200 0.454545
include: Test1 3009 0.332336
include: [Test1, Test2] 1338 0.747384
include: [Test1, Test2, Test3] 877 1.140251
Firefox
Pettern ops/sec msec
Test1.mix(Test2) 19123 0.052293
Test1.mix(Test2).mix(Test3) 6644 0.150512
Test1.mix(Test2, Test3, Test4) 6109 0.163693Test1.mix(Test2, Test3, Test4) 6109 0.163693
(Test1.mix(Test2)).mix(Test3.mix(Test4)) 6925 0.144404
include: Test1 7437 0.134463
include: [Test1, Test2] 3006 0.332668
include: [Test1, Test2, Test3] 2661 0.375799
結論
• Chromeで一番速い– まあまあ予想通り
• IEは突出して遅い– 予想通りだが内部実装が違うことも多少影響か
• includeによる内部mix-inは外部mix-inに比べ極• includeによる内部mix-inは外部mix-inに比べ極端に遅い– 改善の余地あり
• mix-inチェーンより多重継承でまとめてmix-inするほうが速い– 要原因調査
まとめ
• mix.jsのメリット
–親子関係を構築できる
–簡単
– IEでも動く– IEでも動く
–他ライブラリに依存しない
• 今後の予定
– mix.jsでアプリを作る
–パフォーマンス改善