JavaScriptでチーム開発
チーム開発だと、テストとか後でメンバー変わった時のメンテのしやすさとか考えると、ある程度書き方の作法を統一した方がいいので、どうしようかなーと考え中。
何はともあれ、名前空間とクラスの書き方は合わせた方がいいですよね。
例えばこんな風に縛ったり。
ライブラリにはjQueryを使っています。
・base.js
/** * Base namespace. * @static SomeName */ var SomeName = SomeName || {}; // とりあえず適当に ( function() { /** * Set namespaces. * @method namespace * @param {String} namespace */ SomeName.namespace = function( namespace ) { var names = namespace.split( '.' ); ( function( names, parentObject ) { if ( !parentObject ) var parentObject = window; var next = names.shift(); if ( names.length > 0 ) { if ( parentObject[next] == undefined ) parentObject[next] = {}; return arguments.callee( names, parentObject[next] ); } else { if ( parentObject[next] == undefined ) { parentObject[next] = {}; } else { throw Error( 'Namespace "' + next + '" already declared.' ); } } } )( names ); }; /** * Create class. * @method Class * @param {Object} methods The new class's prototype * @return {Function} */ SomeName.Class = function( methods ) { var f = function() { this.init.apply( this, arguments ); }; f.toSingleton = function() { var self = this; var singleton = function() { throw Error( 'This class must be used getInstance.' ); }; singleton.getInstance = function() { if ( singleton.__instance == null ) { var tmp = new self; var res = self.apply( tmp, arguments ); singleton.__instance = ( typeof res == "undefined" ) ? tmp : res; } return singleton.__instance; }; singleton.prototype = self.prototype; return singleton; }; $.extend( f.prototype, methods ); return f; }; /** * Create class was extended by the other class. * @method extend * @param {Object} other The other class * @param {Object} methods Instance methods * @return {Function} */ SomeName.extend = function( other, methods ) { var f = Hoge.Class(); $.extend( f.prototype, other.prototype, methods ); return f; }; } )();
test.js
( function( $ ) { // namespace test SomeName.namespace( 'Test.Base' ); Test.Base.Obj = { xxx: "xxx", yyy: "yyy" }; // redeclare namespace -> コメント外すとエラー // SomeName.namespace( 'Test.Base' ); // base class test Test.Base.Class = SomeName.Class( { init: function( id ) { this._obj = $( id ); }, print: function() { this._obj.html( "Class: ok" ); } } ); // extend class test Test.Base.ClassEx = SomeName.extend( Test.Base.Class, { print: function() { this._obj.html(" Extend class: ok" ); } } ); // singleton class test Test.Base.Singleton = SomeName.extend( Test.Base.Class, { print: function() { this._obj.html( "Singleton class: ok" ); } } ).toSingleton(); } )( jQuery );
test.html
<!doctype html> <html lang="ja"> <head> <meta charset=utf-8" /> <title>Base module test</title> <script type="text/javascript" src="jquery-1.3.2.js"></script> <script type="text/javascript" src="base.js"></script> <script type="text/javascript"> $( function() { new Test.Base.Class( "#result1" ).print(); new Test.Base.ClassEx( "#result2" ).print(); Test.Base.Singleton.getInstance( "#result3" ).print(); Test.Base.Singleton.getInstance().print(); new Test.Base.Singleton( "#result3" ).print(); // エラー } ); </script> </head> <body> <div id="result1"></div> <div id="result2"></div> <div id="result3"></div> </body> </html>
クラスは継承とシングルトンも用意してみました。
シングルトンは最速インターフェース研究会で紹介されているものを拝借!(これ2005年の記事なのがすごすぎ)
コンストラクタをinit()で書くようにしています、ので使えないケースもあるかも。
名前空間の指定をまずファイルの先頭で書いてから名前空間に定義するクラスやオブジェクトを書いて・・・となるので、結構読みやすくなるかなーなんて。
とはいえ、この辺はJavaScriptだと結局どうにでも書けるので、後は規約で縛るしかないかも。
名前空間を関数で指定するメリットとしては、JavaScriptの場合名前空間をオブジェクトで定義して区別するくらいしかないので、重複すると上書きされちゃってどこでエラーが起きてるのか特定しづらくなる場合があるのですが、そういったエラーを一発で特定しやすくなります。
その他に統一したいものとしては、XHRリクエスト、DOM生成、ユニットテスト、APIドキュメント辺りか。
長くなりそうなので、続く・・?