- Rick Waldron @rwaldron, github
- Mathias Bynens @mathias, github
- Schalk Neethling @ossreleasefeed, github
- Kit Cambridge @kitcambridge, github
- Raynos github
- Matias Arriola @MatiasArriola, github
- John Fischer @jfroffice, github
- Idan Gazit @idangazit, github
- Leo Balter @leobalter, github
- Breno Oliveira @garu_rj, github
- Leo Beto Souza @leobetosouza, github
- Ryuichi Okumura @okuryu, github
- Pascal Precht @PascalPrecht, github
- EngForDev engfordev - Hwan Min Hong / MinTaek Kwon @leoinsight / Tw Shim @marocchino, github / Nassol Kim @nassol99, github / Juntai Park @rkJun, github / Minkyu Shim / Gangmin Won / Justin Yoo @justinchronicle / Daeyup Lee
- Marco Trulla @marcotrulla, github
- Alex Navasardyan @alexnavasardyan, github
- Mihai Paun @mihaipaun, github
- Evgeny Mandrikov @_godin_, github
- Sofish Lin @sofish, github
- Дејан Димић @dejan_dimic, github
- Miloš Gavrilović @gavrisimo, github
- Duc Nguyen @ducntq, github
- James Young @jamsyoung, github
Rebecca Murphey
"成功を収めるプロジェクトをうまく管理することの一つが自分でコードを書いて実現するということではありません。もし多くの人があなたのコードを利用しているなら、仕様の中にはあなたの好みではなく、最大限に明確なコードを書きましょう。" - Idan Gazit
Idan Gazit
- ORIGINAL
- German
- French
- Spanish
- Portuguese - Brazil
- Korean
- Japanese
- Italian
- Russian
- Romanian
- 简体中文
- Serbian - cyrilic alphabet
- Serbian - latin aplphabet
- JavaScript Plugin for Sonar
- Plato
- jsPerf
- jsFiddle
- jsbin
- JavaScript Lint (JSL)
- jshint
- jslint
- Editorconfig
下記の事項は 1) 不完全、2) 必読ということを熟考しなければなりません。私はこれらの作者によるスタイルに常に同意はしていませんが、彼らは一貫性があるため信頼できるのも確かです。その上、これらは言語の世界では権威があるものです。
- Baseline For Front End Developers
- Eloquent JavaScript
- JavaScript, JavaScript
- Adventures in JavaScript Development
- Perfection Kills
- Douglas Crockford's Wrrrld Wide Web
- JS Assessment
- Leveraging Code Quality Tools by Anton Kovalyov
プロジェクトは常にプロダクションで使うための準備の中にチェックやテスト、圧縮などをするためのいくつかの包括的な手法を含めるように努力するべきです。このタスクのために、Ben Almanによるgruntは他と比べようもないほど素晴らしく、このレポジトリの "kits/" ディレクトリも正式に置き換えられました。
ユースケースデモを"テスト"として見なしてはいけません。下記の事項はテストフレームワークのリストで、どれも他の何よりも支持されているものです。
- スペース
- 美しい構文
- 型のチェック(jQeury Core Style Guidelinesの作法)
- 条件文の評価
- 実際のスタイル
- ネーミング
- 雑則
- ネイティブオブジェクトとホストオブジェクト
- コメント
- 1つの言語としてのコード
下記のセクションではモダンなJavaScriptの開発のための_合理的な_スタイルガイドを説明していますが、規範的になれという意味ではありません。最も重要なことは一貫性のあるコードスタイル法則ということです。どんなものでもあなたのプロジェクトのために選ぶスタイルは一貫性のある法則であるべきです。一貫性、可読性、メンテナンス性のあるコードスタイルにするためにあなたのプロジェクトのコミットメントとしてこのドキュメントへリンクしてください。
- スペースとタブを混ぜてはいけません。
- プロジェクトの新しく始める時、コードを書く前にソフトインデント(スペース)かタブか選択するようにこの法則を検討してください。
- 可読性をのために、私はエディターのインデントサイズを2文字にするようにいつも推奨しています — これは2つのスペースまたはタブを2つのスペースに表現することを意味しています。
- もしあなたのエディターが"不可視文字を表示する"設定があるなら常にオンにしてください。このプラクティスのメリットは:
- 一貫性を強制できる
- 行末のスペースをなくせる
- スペースの空行をなくせる
- コミットと差分が読みやすくなる
-
A. 丸括弧、中括弧、改行
// if/else/for/while/try は常にスペースをもち、波括弧が複数の行に架かるようにします // これは可読性を促進します // 2.A.1.1 // あまりに読みにくい構文の例 if(condition) doSomething(); while(condition) iterating++; for(var i=0;i<100;i++) someIterativeFn(); // 2.A.1.1 // 可読性を促進するためにスペースを使います if ( condition ) { // 文 } while ( condition ) { // 文 } for ( var i = 0; i < 100; i++ ) { // 文 } // より良い例: var i, length = 100; for ( i = 0; i < length; i++ ) { // 文 } // または... var i = 0, length = 100; for ( ; i < length; i++ ) { // 文 } var prop; for ( prop in object ) { // 文 } if ( true ) { // 文 } else { // 文 }
B. 割り当て、宣言、関数(名前、式、コンストラクター)
// 2.B.1.1 // 変数 var foo = "bar", num = 1, undef; // リテラル表記: var array = [], object = {}; // 2.B.1.2 // 可読性を促進するためにスコープ(関数)ごとに1つだけ `var` を使用します // 宣言するリストはすっきりしている状態を保ちます(同様に少ないキーストロークを守ります) // 悪い例 var foo = ""; var bar = ""; var qux; // 良い例 var foo = "", bar = "", quux; // または var // ここにコメントをつけます foo = "", bar = "", quux; // 2.B.1.3 // var文は常にそれぞれのスコープ(関数)の最初になくてはなりません。 // 悪い例 function foo() { // ここにいくつかの文を書きます var bar = "", qux; } // 良い例 function foo() { var bar = "", qux; // すべての文は変数の宣言の後に書きます } // 2.B.1.4 // ECMAScript 6のconstやletもまた同様です。 // 悪い例 function foo() { let foo, bar; if ( condition ) { bar = ""; // statements } } // 良い例 function foo() { let foo; if ( condition ) { let bar = ""; // statements } }
// 2.B.2.1 // 名前つきの関数の宣言 function foo( arg1, argN ) { } // 関数の使い方 foo( arg1, argN ); // 2.B.2.2 // 名前つきの関数の宣言 function square( number ) { return number * number; } // 関数の使い方 square( 10 ); // とても不自然な継続渡しスタイル function square( number, callback ) { callback( number * number ); } square( 10, function( square ) { // コールバック関数の文 }); // 2.B.2.3 // 式による関数の宣言 var square = function( number ) { // 値や関連する何かを返します return number * number; }; // 識別子と式による関数の宣言 // この望ましい形では、スタックトレースの中で自ら呼び出せる識別子を // 持つことができます var factorial = function factorial( number ) { if ( number < 2 ) { return 1; } return number * factorial( number-1 ); }; // 2.B.2.4 // コンストラクターの宣言 function FooBar( options ) { this.options = options; } // コンストラクターの使い方 var fooBar = new FooBar({ a: "alpha" }); fooBar.options; // { a: "alpha" }
C. 例外や些細なこと
// 2.C.1.1 // コールバックと関数 foo(function() { // ここには実行される関数の最初の括弧と"function"との間には // スペースがないことを注意してください }); // 配列を受け取る関数、スペースはなし foo([ "alpha", "beta" ]); // 2.C.1.2 // オブジェクトを受け取る関数、スペースなし foo({ a: "alpha", b: "beta" }); // 1つの文字列を受け取る場合、スペースなし foo("bar"); // 中でグループ化された括弧、スペースなし if ( !("foo" in obj) ) { }
D. 一貫性が常に勝つ
セクション2.A-2.Cのスペースのルールはよりシンプルで高い目的のための提案としたセットで一貫性に繋がるものです。 "中のスペース"のようなフォーマットの好みは任意で検討するように気をつけなければいけませんが、1つのスタイルがあなたのプロジェクトのソース全体で揃っていなければなりません。
// 2.D.1.1 if (condition) { // 文 } while (condition) { // 文 } for (var i = 0; i < 100; i++) { // 文 } if (true) { // 文 } else { // 文 }
E. クオート
あなたの好みがシングルクオートだろうとダブルクオートだろうとどうでもいい事です。これらはJavaScriptの解析においては違いはありません。絶対に強制されることは一貫性に繋がります。同じプロジェクトの中でクオートを混ぜないでください。1つのスタイルを選び、それにこだわってください。
F. 行末と空行
スペースは読めない変更点を生み、差分を壊します。コミット前に、自動で行末のスペースや空行のスペースを削除する処理を行うことを検討してください。
-
型のチェック(jQeury Core Style Guidelinesの作法)
A. 実際の型
文字列:
typeof variable === "string"
数値:
typeof variable === "number"
ブール値:
typeof variable === "boolean"
オブジェクト:
typeof variable === "object"
配列:
Array.isArray( arrayLikeObject ) (可能な限り)
ノード:
elem.nodeType === 1
null:
variable === null
nullまたはundefined:
variable == null
undefined:
グローバル変数:
typeof variable === "undefined"
ローカル変数:
variable === undefined
プロパティ:
object.prop === undefined object.hasOwnProperty( prop ) "prop" in object
B. 強制された型
次の実装を考えてみてください。
こういうHTMLがあったとします:
<input type="text" id="foo-input" value="1">
// 3.B.1.1 // `foo` は `0` という値で宣言されて、型は `number` になります var foo = 0; // typeof foo; // "number" ... // あなたのコードのどこかで、input要素から値を取得して // `foo` を更新する必要があります foo = document.getElementById("foo-input").value; // もしあなたがこの時点で `typeof foo` をテストした場合、次のような // ロジックがあるとその結果は `string` となることを意味します。 if ( foo === 1 ) { importantTask(); } // `importantTask()` はたとえ `foo` が "1" だとしても評価されないでしょう。 // 3.B.1.2 // + または - といった単項演算子による型強制を使って、この問題を回避できます: foo = +document.getElementById("foo-input").value; // ^ この + 演算子は右側の値をnumberに変換します // typeof foo; // "number" if ( foo === 1 ) { importantTask(); } // こうすれば `importantTask()` は呼び出されます
これらは同じように強制的に変換するいくつかの方法です:
// 3.B.2.1 var number = 1, string = "1", bool = false; number; // 1 number + ""; // "1" string; // "1" +string; // 1 +string++; // 1 string; // 2 bool; // false +bool; // 0 bool + ""; // "false"
// 3.B.2.2 var number = 1, string = "1", bool = true; string === number; // false string === number + ""; // true +string === number; // true bool === number; // false +bool === number; // true bool === string; // false bool === !!string; // true
// 3.B.2.3 var array = [ "a", "b", "c" ]; !!~array.indexOf("a"); // true !!~array.indexOf("b"); // true !!~array.indexOf("c"); // true !!~array.indexOf("d"); // false // 上記のやり方は"無駄に賢すぎる"と考えるべきです // 次のように、indexOfが返した値を比較する明確なアプローチに // してみましょう。 if ( array.indexOf( "a" ) >= 0 ) { // ... }
// 3.B.2.3 var num = 2.5; parseInt( num, 10 ); // これは次の場合と同じです ~~num; num >> 0; num >>> 0; // どれも結果は2になります // しかし、負の値の場合は異なった扱いをされることを覚えておきましょう var neg = -2.5; parseInt( neg, 10 ); // これは次の場合と同じです ~~neg; neg >> 0; // これはどれも-2になります // 一方で... neg >>> 0; // この結果は4294967294となります
-
// 4.1.1 // 配列の長さがあるかだけを評価する場合は、次の代わりに: if ( array.length > 0 ) ... // このように真偽を評価すればいいでしょう: if ( array.length ) ... // 4.1.2 // 配列が空かどうかだけを評価する場合は次の代わりに: if ( array.length === 0 ) ... // このように真偽を評価すればいいでしょう: if ( !array.length ) ... // 4.1.3 // 文字列が空ではないことだけを評価する場合は次の代わりに: if ( string !== "" ) ... // このように評価すればいいでしょう: if ( string ) ... // 4.1.4 // 文字列が空であることだけを評価する場合は次の代わりに: if ( string === "" ) ... // このように真偽を評価すればいいでしょう: if ( !string ) ... // 4.1.5 // 参照先がtrueかどうかだけ評価する場合は次の代わりに: if ( foo === true ) ... // このように評価します(おわかりのとおり、これは組み込まれた機能です): if ( foo ) ... // 4.1.6 // 参照先がfalseかどうかを評価する場合は次の代わりに: if ( foo === false ) ... // trueでの評価を強制させるため、ネゲートします if ( !foo ) ... // 注意点としてこの場合は0、""、null、undefined、NaNといった値にも // マッチします。もしfalseに限定する必要があるのであれば次のようにします if ( foo === false ) ... // 4.1.7 // 参照先がfalse、""、0ではなく、nullまたはundefinedかどうかだけを // 評価する場合は次の代わりに: if ( foo === null || foo === undefined ) ... // 次のように==を使用して型の変換を利用します if ( foo == null ) ... // 覚えておいてください: ==を使うと、nullはnullおよびundefinedの両方とマッチします。 // しかし、falseと0にはマッチしません null == undefined
常にベストで正確な結果のための評価をしましょう - 上記はガイドラインであって、ドグマではありません。
// 4.2.1 // 型の変換と評価の注意書き // `==` よりも `===` を選びましょう(あいまいな型の評価が必要でない限り) // ===は次のように型を変換しません: "1" === 1; // false // ==は次のように型を変換します: "1" == 1; // true // 4.2.2 // ブール値、trueな値とfalseな値 // ブール値: true, false // truthy(訳注:真のような)値: "foo", 1 // falsy(訳注:偽のような)値: "", 0, null, undefined, NaN, void 0
-
// 5.1.1 // 実践的なモジュール (function( global ) { var Module = (function() { var data = "secret"; return { // 何らかのブール値のプロパティ bool: true, // 何らかの文字列の値 string: "a string", // 配列のプロパティ array: [ 1, 2, 3, 4 ], // オブジェクトのプロパティ object: { lang: "en-Us" }, getData: function() { // 現在の`data`の値を取得する return data; }, setData: function( value ) { // `data`の値をセットしてそれを返す return ( data = value ); } }; })(); // その他のコードがここに入る // グローバルオブジェクトからモジュールが見えるようにします global.Module = Module; })( this );
// 5.2.1 // 実践的なコンストラクター (function( global ) { function Ctor( foo ) { this.foo = foo; return this; } Ctor.prototype.getFoo = function() { return this.foo; }; Ctor.prototype.setFoo = function( val ) { return ( this.foo = val ); }; // `new`を使わずにコンストラクターを呼び出すにはこのようにします: var ctor = function( foo ) { return new Ctor( foo ); }; // グローバルオブジェクトからモジュールが見えるようにします global.ctor = ctor; })( this );
-
A. あなたは人間コンパイラではありません。そうなろうとしてはいけません。
次のコードはひどいネーミングの例です:
// 6.A.1.1 // 悪い名前を使ったコードの例 function q(s) { return document.querySelectorAll(s); } var i,a=[],els=q("#foo"); for(i=0;i<els.length;i++){a.push(els[i]);}
紛れもなくこう書いたほうがいいでしょう。
これはロジックは同じですが、より親切で考えられたネーミングです(そして読みやすい構造になっています):
// 6.A.2.1 // 改善したネーミングを使ったコードの例 function query( selector ) { return document.querySelectorAll( selector ); } var idx = 0, elements = [], matches = query("#foo"), length = matches.length; for ( ; idx < length; idx++ ) { elements.push( matches[ idx ] ); }
ネーミングの観点でいくつか補足すると:
// 6.A.3.1 // 文字列のネーミング `dog` は文字列です // 6.A.3.2 // 配列のネーミング `dogs` は `dog` という文字列の配列です // 6.A.3.3 // 関数、オブジェクト、インスタンスなどのネーミング camelCase; function と var による宣言 // 6.A.3.4 // コンストラクターやプロトタイプなどのネーミング PascalCase; コンストラクター // 6.A.3.5 // 正規表現のネーミング rDesc = //; // 6.A.3.6 // Google Closure Library Style Guideより functionNamesLikeThis; variableNamesLikeThis; ConstructorNamesLikeThis; EnumNamesLikeThis; methodNamesLikeThis; SYMBOLIC_CONSTANTS_LIKE_THIS;
B.
this
の扱い後から呼び出される
BoundFunction
(訳注:thisが束縛された関数)を定義する場合は、よく使われるcall
やapply
ではなく、.bind( this )
か、または同等の方法を使いましょう。selfの別名を作るのは、他に方法がない場合のみにするべきです。// 6.B.1 function Device( opts ) { this.value = null; // これは非同期のストリームをオープンし // 継続的に呼び出されます stream.read( opts.path, function( data ) { // このインスタンスの現在の値を // データストリームの最新の値で更新します this.value = data; }.bind(this) ); // デバイスのインスタンスから頻繁に発行される // イベントを絞ります setInterval(function() { // 絞ったイベントを発行します this.emit("event"); }.bind(this), opts.freq || 100 ); } // EventEmitterを継承したかのように装います ;)
もし利用できない場合でも最近の多くのJavaScriptライブラリには
.bind
と同様な機能があります。// 6.B.2 // 例)lodash/underscoreの_.bind() function Device( opts ) { this.value = null; stream.read( opts.path, _.bind(function( data ) { this.value = data; }, this) ); setInterval(_.bind(function() { this.emit("event"); }, this), opts.freq || 100 ); } // 例)jQuery.proxy function Device( opts ) { this.value = null; stream.read( opts.path, jQuery.proxy(function( data ) { this.value = data; }, this) ); setInterval( jQuery.proxy(function() { this.emit("event"); }, this), opts.freq || 100 ); } // 例)dojo.hitch function Device( opts ) { this.value = null; stream.read( opts.path, dojo.hitch( this, function( data ) { this.value = data; }) ); setInterval( dojo.hitch( this, function() { this.emit("event"); }), opts.freq || 100 ); }
最後の手段が、
this
の別名self
を識別子として作ることです。しかしバグの原因になりやすいため、この方法は可能な限り避けるべきです。// 6.B.3 function Device( opts ) { var self = this; this.value = null; stream.read( opts.path, function( data ) { self.value = data; }); setInterval(function() { self.emit("event"); }, opts.freq || 100 ); }
C.
thisArg
を使うES 5.1組み込みのいつくかのプロトタイプメソッドは、特別な
thisArg
シグネチャに対応しています。可能な限り利用するべきです。// 6.C.1 var obj; obj = { f: "foo", b: "bar", q: "qux" }; Object.keys( obj ).forEach(function( key ) { // |this|は`obj`への参照 console.log( this[ key ] ); }, obj ); // <-- 最後の引数が`thisArg` // 結果は... // "foo" // "bar" // "qux"
thisArg
はArray.prototype.every
、Array.prototype.forEach
、Array.prototype.some
、Array.prototype.map
、Array.prototype.filter
で利用できます。 -
このセクションは、ドグマとはいえないまでも、JavaScriptプログラミングをより良くこなすための、探究的なプラクティスの助けとなるアイデアおよびコンセプトを提供します。
A.
switch
の使用はできるだけ避けるべきです。モダンなメソッドトレースは、switchを含む関数をブラックリスト入りさせるでしょうこれは最新のFirefoxとChromeでの
switch
文の実行の大幅な改善です。 http://jsperf.com/switch-vs-object-literal-vs-module注目すべき改善点はここでも確認できます: rwaldron#13
// 7.A.1.1 // switch文の例 switch( foo ) { case "alpha": alpha(); break; case "beta": beta(); break; default: // デフォルトのための何か break; } // 7.A.1.2 // `cases`とデリゲートする関数をオブジェクトに保存する代わりのやり方 // 再利用と再構成が可能になる var cases, delegator; // 説明用にreturnのみ記載 cases = { alpha: function() { // ステートメント // リターン return [ "Alpha", arguments.length ]; }, beta: function() { // ステートメント // リターン return [ "Beta", arguments.length ]; }, _default: function() { // ステートメント // リターン return [ "Default", arguments.length ]; } }; delegator = function() { var args, key, delegate; // 引数を配列に変換 args = [].slice.call( arguments ); // caseの部分を引数からとりだす key = args.shift(); // まずデフォルトケースをアサインする delegate = cases._default; // 処理をデリゲートする関数を取り出す if ( cases.hasOwnProperty( key ) ) { delegate = cases[ key ]; } // スコープ引数も指定可能 // この例では |null| にしている return delegate.apply( null, args ); }; // 7.A.1.3 // (7.A.1.2のAPIを使っています) delegator( "alpha", 1, 2, 3, 4, 5 ); // [ "Alpha", 5 ] // もちろん、`case`には簡単に算術条件も使える var caseKey, someUserInput; // たとえばフォーム入力値 someUserInput = 9; if ( someUserInput > 10 ) { caseKey = "alpha"; } else { caseKey = "beta"; } // または caseKey = someUserInput > 10 ? "alpha" : "beta"; // そして delegator( caseKey, someUserInput ); // [ "Beta", 1 ] // そしてもちろん delegator(); // [ "Default", 0 ]
B. すぐにReturnすることで、コードの可読性が上がり、わずかにパフォーマンスも向上します
// 7.B.1.1 // 悪い例: function returnLate( foo ) { var ret; if ( foo ) { ret = "foo"; } else { ret = "quux"; } return ret; } // 良い例: function returnEarly( foo ) { if ( foo ) { return "foo"; } return "quux"; }
-
基本的な原則はここにある通りです:
このコンセプトを補足するために、次のプレゼンテーションを見てください:
http://www.everytalk.tv/talks/441-JSConf-Everything-is-Permitted-Extending-Built-ins
- 主題としてコード上に単一行で書きます
- 複数行でも良い
- 行末のコメントは禁止!
- JSDocのスタイルは良いですが大幅な時間を要します
-
保守する人が要求するとおり、その言語が何であれ、プログラムは1つの言語によって書かれるべきです。
このドキュメントを基本的なスタイルガイドとして引用しているいくつかのプロジェクトは、そのプロジェクトの作者が特別に指定しない限りコンマを最初に置くコードフォーマットを受け入れません。