プロトタイプチェーンを意識したJavaScriptを考える
今年のワールドカップはドイツが優勝すると信じてやまないnishigoです。
最近は開発でもっぱらJavaScriptしか触っていません。
普段はPHPでコードを書くことのほうが多いので、私のようにJavaScriptは
どうしてもprototype.js等のライブラリに頼りきってしまう、
なんて方も多いのではないでしょうか。
そんな苦手意識を少しでも克服する為に、
あまり取り上げられることのないコード統一化TipsをJavaScriptの特性に触れながら
解説していきます。
Array Object
PHPerであれば、PHPの豊富な組み込み関数をJavaScriptでも気兼ねなく使いたいと
思ったことのある方はいるでしょう。
php.jsではそんなPHPでよく利用する組み込み関数を多数メソッドとして定義して
くれています。
http://phpjs.org
そしてこのphp.jsが定義している各メソッドは非常に厳密であり、
ソースを読むことでJavaScriptの言語としての特性を理解する手助けをしてくれます。
例で、is_array()のソースを読んでいきましょう。
var is_array = function(arr) {
return typeof arr === 'object' &&
typeof arr.length === 'number' &&
!(arr.propertyIsEnumerable('length')) &&
typeof arr.splice === 'function';
};
このreturn文の一行目では、引数arrが’object’であることを確認し、
ここでオブジェクトか配列、もしくはnullであるかを確認しています。
二行目では引数のlengthプロパティに数値が割り当てられてるかの確認。
三行目にはlengthプロパティがfor in文で回せるかの確認。
そして最後に配列の特性であるspliceメソッドを持ち得ているかの確認です。
このようにJavaScriptの配列はtypeof演算子でも’object’と認識してしまう程
分かりにくいものとなっていて、他のプログラミング言語と比べて配列とオブジェクト
の使い分けが難しいところでもあります。
もし対象となるマッパーオブジェクトが短いプロパティ名や
数値のみで構成されていて、それらをループで回したいのであれば、
思い切って二次元配列にしてしまいfor文でループしたほうが良い場合もあります。
PHPであれば下記のようにforeach文で回せば済む話でしょう。
foreach ($values as $key => $value) {
// done
}
foreach文に変わるものとしてJavaScriptではfor in文を思い浮かべるかもしれませんが、
JavaScriptの配列はあくまでオブジェクトなので、すべてのプロパティを列挙します。
つまり、プロトタイプチェーン上のプロパティすら列挙してしまい、余計なプロパティまで
列挙される処理はあまり好ましくありません。
可能であればfor文で記述したほうが良いでしょう。
var techMembers = [ ['nishigo1', 0], ['nishigo2', 2], .. ];
var i;
for (i = 0; i < techMembers.length; i += 1) {
var post = techMembers[1] === 0 ? 'staff' : 'manager';
document.writeln(post + 'の' + techMembers[0] + 'です');
}
配列となると、まず空の配列を作りそこに値を代入もしくは格納していくという
処理を書くこともあるでしょう。
// PHP_code
$data = array();
foreach ($foo as $value) {
$data[] = $value;
}
JavaScriptでは空の配列オブジェクト(厳密にはArray.prototypeがある為空ではありませんが)
を定義する際にはリテラル記法で記述しましょう。
var techMembers = []; // ○
var techMembers = new Array(); // ×
なぜならnew 演算子でのオブジェクト定義はvalueOfメソッドを持ってしまっているからです。
ラップされた値を返すvalueOfメソッドを使う機会は皆無であるので、
new Arrayやnew Object の利用はすべきではありません。
(また、new演算子を使用するオブジェクトは一文字目が大文字であるべきと
いう暗黙のルールもあります。)
Function Object
JavaScriptのfunction文は、どこに書かれていようとも該当スコープの
先頭に移動させられる性質を持っています。
これによって関数をスコープ内であればどこからでも呼び出せますが、
省略記法でなくvar文で記述(function式)することをオススメします。
(無論グローバル関数を置かないことを前提として)
var foo = function () { };
なぜならJavaScriptを書いているとクロージャのように変数に格納していく
機会のほうが圧倒的に多いであろうからです。
var addSelectMember = function(members, func) {
var lastMember = 0;
if (is_array(members) && typeof func === 'function') {
var addEvent = function(post) {
var idName = post === 2 ? 'manager' : 'staff';
document.getElementById(idName).setAttibute('onClick', func(this));
};
var i;
for (i = 0; i < members.length; i += 1) {
if (lastMember < members[i]) lastMember = i;
addEvent.call(this, members[i]);
}
}
return lastMember;
} (/* Array Object, Function Object */);
function文で統一されたコードの方が前文で記述されることで
難しい処理もある程度は可読性があがります。
PHPでは5.3から匿名関数が使用できますが、
5.2以前で開発を行っている方は多少不便に感じるかもしれません。
しかし実はなんてことはない、
普段JavaScriptでパブリックメソッドを記述する方法と大差ないでしょう。
var foo = {
setMaxLength : function() {
// done
},
....
};
foo.moo = function() { };
そして、JavaScriptと言ったら避けては通れないIEの数々の壁(?)ですが、
そんなJScriptエンジンさんでも気に入ってる部分があるのでご紹介 :->
1つ目は、オブジェクトプロパティに次の要素が無いのにカンマをつけると
IEではランタイムエラーが発生する点。
hogeObject = {
textAlign : 'left',
font : '15px',
color : '#FFF', // Syntax error ;-<
};
こういったところをFirefoxは無視してしまうので後々IEで
ブラウザチェックするという場面で戸惑うことも多いですね。
この部分に関してのみ言えばIEが構文チェックに厳密な点もあると言えるでしょう。
2つ目は、IE6,7ではsetAttribute(もしくはgetAttribute)での属性名はlowerCamelで記述する必要がある点。
element.setAttribute("maxlength", 5); => element.setAttribute("maxLength", 5);
prototype.jsではEvent.observe()のイベント名で’mousedown’のように記述しますが、
上記のようにlowerCamel記法でJavaScriptらしい記述に統一できればな、と個人的には思います。
と、IEについてはこれ以上書くことが見つかりません。。。
IE9でのChockraエンジンに期待を寄せつつJavaScriptの未来に期待したいと思います。
最後に全体を通しての細かい点ですが、ホワイトスペースや括弧の記述なども
開発者にとっては気になるところかもしれません。
数あるJavaScriptのライブラリでも、if文に{}がついてないことはよくあります。
しかしそのような場合は{}内の処理を同じ行にまとめ、そして2つ以上命令文を書かないの
が通例です。
そしてifやswitch文等の括弧とのホワイトスペースは関数呼び出しと区別するために
つけたほうがよいかもしれません。
if(typeof foo === 'object'){ /* */ }; //ホワイトスペースなし
if (typeof foo === 'function') {
// ホワイトスペースあり
};
Element.hasAttribute(); // FunctionObject
今回取り上げる項目は以上ですが、変数やメソッドの命名規則だけでなく
こうした細かいコード記述理論も開発チーム内で統一・共有されると、
より美しいコードが生まれてくるかもしれません。
ディスカッション
コメント一覧
まだ、コメントがありません