JavaScript Patterns 2011.01.16 @ sapporo.js @havanaclub_
Jan 15, 2015
JavaScript Patterns2011.01.16 @ sapporo.js
@havanaclub_
自己紹介
•帯広から来ました
帯広
•超寒い
帯広
•ー17度
帯広
•雪:帰りがやばそう
•去年の9月くらい発売•例によってYohoo labs産(YSlowの作者Stoyan Stefanov)
• デザインパターン•コーディングパターン•アンチパターン•ライブラリ書きたい人向け
•良いところ:•ライブラリ実装者のノウハウこもりまくり
•悪いところ:•一見さんお断り• GoodPartsとか読みましょうって書いてある
基本部門
Global汚染の弊害
•よくわからんスクリプトが動的に読み込まれたときに動かんくなったりする
•広告JavaScript• ライブラリ相性•アクセス解析
ECMSScript 5strict mode
• var で確保された変数以外への代入はエラー(like Perl’s “use strict”)
functon some () {“use strict”;// do something...ubar = ‘dedededfe’ // error
}
ループとか
効率よくループ実行
for (var i = 0; i < myarray.length; i++ ) {// = some
}
for (var i = 0, max = myarray.length; i < max ;i++ ) {// = some
}
for loopCashing collection length
190 times faster(IE7)
毎回DOM問い合わせが入るのでキャッシュ
for in と for の使い分け
for in loop
• array 以外の数え上げに利用すべき• arrayにも利用可能ではあるがプロパティがセットされてると誤爆する
•数え上げ順序が不定
for in loop : 2
• prototype chainで継承してきた値のフィルタにはobj.hasOwnProperty()を使う
var man = { heads : 2, legs : 2 };Object.prototype.clne = function() {};
for (var i in man) {if (man.hasOwnProperty(i)) {
console.log(i, ‘:’, man[i]);} # => heads:2
} # legs:2
GoodPartsにも同記述
比較演算子
暗黙の型キャストを避ける
•特に比較の場合。• type aware な === または !== を使用すべき
var zero = 0;if (zero === false) {
// good}
if (zero == false) {// anti pattern
}
数値データの解析
parseInt
• 数字が0ではじまっていると8進で解釈される
• parseIntと基数はセットで指定•Numberも使える
// anti patternparseInt(“012”) => 10
// good wayparseInt(“012”, 10) => 12Number(“012”) => 12
GoodPartsの後ろの方にも同記述
書き方系
•コーディング規約•命名規約•コメントの書き方• APIドキュメントの書き方• YUI doc(javadocみたいなの)• JSLint
オブジェクト関係
普通のコンストラクタ
•まあ普通
var Person function(name) {this.name = name;this.say = function(){ return “ test “ + this.name };
}
var person = new Person(“aaa”);
プロパティを変更させたくない(private
化)
private
•クロージャとの組み合わせでまあ可能
function Gadget () { var name = “aaaa”;
this.getName = function () { return name};this.setName = function (n) { name = n };
}
var g = new Gadget(); g.getName(); g.setName(‘test’);g.name = “change”;
オブジェクト関係
new を忘れると
• thisがグローバルオブジェクトを指す• ECMAScript 5 strict modeだとグローバルオブジェクトを指さなく出来る
var Person = function(name) {this.name = name;this.say = function(){ return “ test “ + this.name };
}
var person = Person(“aaa”);person.name // => this will reference window.name or global symbol ‘name’
コンストラクタでthis 以外を返す
• that という名前にしておくと良い(命名規約的に)
• Singletonもこのパタンで
var Waffle = function() {var that = { msg : ‘yummy’ };return that;
}
var waffle = new Waffle(); // => {msg: ‘yummy’};
newが無くてもオブジェクトnew
• newの自己呼び出しテクニック• thisが関数ローカルスコープでなさそうだったらあらためてnew
function Waffle() {if(!(this instanceof Waffle)) {
return new Waffle();}
this.tastes = ‘yummy’ ;}var waffle = Waffle(); // is instance of Waffle
エラー関係
•実はnameとmessage属性が有るオブジェクトならなんでもthrowできる
•
try {throw {
name : “someError”,message : “error test”,test : function() { return name }
};} catch (e) {
console.log(e.test());}
エラー関係 (2)使い道
•エラーの付加情報とかを付けるのに便利
•でも普通にErrorサブクラス作った方が良い
try {throw {
name : “someError”,message : “error test”,errorStatus : 312
};} catch (e) {
return [message, e.errorStatus];}
ふつうの
•直接変更させたくない•入力値のバリデーション等
function Gadget () { this.name = “aaaa”;
this.getName = function () { return name};this.setName = function (n) { name = n };
}
var g = new Gadget();g.name = “changed”;
割と良く使うクロージャ利用:ロギング
•ロガーとクロージャの相性はかなり良い
var blog = Blog.load( {blog_id: 2} );var entry = blog.entries().first();
var logger = function(msg) { console.log(“Blog : “ + blog.id + “ Entry : “ + entry.id + msg)};
logger(“see this”) / /=> “Blog id : 2 Entry id : 3 see this”
部分適用版var blog = Blog.load( {blog_id: 2} );var entry = blog.entry();
function cusutom_logger(blog_id, entry_id) {return function(msg) {
console.log(“Blog : “ + blog_id + “ Entry : “ + entry_id + msg)};}
var logger = cusutom_logger(blog.id, entry.id);logger(“see this”) / /=> “Blog id : 2 Entry id : 3 see this”
その他の内容
•関数•Curryingとかメモ化作成時分岐とか•オブジェクト生成•名前空間とか依存宣言とかModule• デザインパターンのJavaScript版• Deployment(圧縮等)
まとめ
•読むとjQueryとか作ってる人のきもちがわかるかも
宣伝•Hokkaido.pm #4 やります• 2/19 今回のゲスト:yusukebe さん•エロサイト管理者の憂鬱とか話してくれるらしいよ
• C++勉強会 2/26 • (東京のBoost勉強会のUSTみる予定)
補足:Curry化$(‘div1’).onclick = function () {
alert (‘aaa’);}$(‘div2’).onclick = function () {
alert (‘bbb’);}....
• onclickでそれぞれのdivに違うメッセージを出すパターン
•増えてくるとメンテナンスがめんどい
補足:Curry化(2)$(‘div1’).onclick = gen_alert(‘aaa’);$(‘div2’).onclick = gen_alert(‘bbb’);function gen_alert(msg) {
return function { alert(msg) };}
•関数のカスタマイズ=引数の消去•「指定したメッセージをalertで表示する引数なしの関数」をつくる関数をつくり、それの返値をコールバック登録
補足:Cコールバックtypedef int (*CALLBACK)(* void); // pointer type for int func(void *)typedef struct {
CALLBACK handler;void * option;
} callback_data;
callback_data callback;void register_callback (CALLBACK f, void* opt) {
callback.handler = f; callback.option = opt;}void invoke_callback() {
CALLBACK f = callback.handler;f(callback.option);
}
char * msg = “message”;int speak() { printf (“%s”, (char *)void) };main () {
register_callback((CALLBACK)speak, (void *)msg);invoke_callback();
}
• (void *)でオプションパラメータを登録できるようにするのが定石