JavaScriptには多くの素晴らしいスタイルガイドがあります。そのため、さらに別のスタイルガイドを作成する必要はありません。代わりに、この章ではメタスタイルルールについて説明し、既存のスタイルガイドと確立されたベストプラクティスを調査します。また、私が好む、より議論の余地のあるプラクティスについても言及します。既存のスタイルガイドを置き換えるのではなく、補完することを目的としています。
これは私が好むスタイルガイドです:
さらに、メタに関する2つのスタイルガイドがあります
このセクションでは、一般的なコード記述のヒントについて説明します。
一貫性のあるコードを書くための重要なルールは2つあります。最初のルールは、新しいプロジェクトを開始する場合、スタイルを考え出し、文書化し、どこでもそれを守ることです。チームが大きいほど、JSHintなどのツールを使用して、スタイルの遵守を自動的にチェックすることが重要になります。スタイルに関しては、多くの決定を下す必要があります。それらのほとんどは、一般的に合意された回答があります。その他はプロジェクトごとに定義する必要があります。例えば:
var
ステートメントをどのように、どこに書くか2番目のルールは、既存のプロジェクトに参加する場合、そのルールを厳密に守ることです (たとえ同意しなくても)。
デバッグはプログラムを書くことの2倍難しいことは誰もが知っています。そのため、書くときにできるだけ賢くしていると、どうやってデバッグするのでしょうか?—Brian Kernighan
ほとんどのコードでは、読むのにかかる時間は書くのにかかる時間よりもはるかに長くなります。そのため、前者をできるだけ簡単にすることが重要です。そのためのガイドラインをいくつか紹介します
redBalloon
はrdBlln
よりも読みやすいです。ほとんどのコードベースは、新しいアイデアや概念でいっぱいです。つまり、コードベースで作業したい場合は、それらのアイデアと概念を学ぶ必要があります。教科書とは対照的に、コードの追加の課題は、人々がそれを線形に読まないことです。彼らはどこにでも飛び込み、何が起こっているのかを大まかに理解できるはずです。コードベースの3つの部分が役立ちます
多くの賢さは、これらの最適化に向けられています。ただし、通常は必要ありません。一方では、JavaScriptエンジンはますますスマートになり、確立されたパターンに従うコードの速度を自動的に最適化します。一方、縮小ツール (第32章) は、コードを可能な限り小さくするように書き直します。どちらの場合も、ツールはあなたのために賢いため、あなたが賢くなる必要はありません。
コードのパフォーマンスを最適化する以外に選択肢がない場合があります。その場合は、必ず正しい部分を測定して最適化してください。ブラウザでは、問題は多くの場合DOMとHTMLに関連しており、言語自体には関連していません。
JavaScriptプログラマーの大多数は、次のベストプラクティスに同意しています。
常に厳密な等価性 (===
) と厳密な非等価性 (!==
) を使用します。このルールから逸脱しないことをお勧めします。次の2つの条件は同等ですが、私は最初の条件を好みます。
if
(
x
!==
undefined
&&
x
!==
null
)
...
// my choice
if
(
x
!=
null
)
...
// equivalent
中括弧がコードブロックを区切る言語では、ブレーススタイルは、それらの中括弧をどこに配置するかを決定します。Cのような言語 (JavaやJavaScriptなど) では、2つのブレーススタイルが最も一般的です。Allmanスタイルと1TBSです。
ステートメントにブロックが含まれている場合、そのブロックはステートメントの先頭とはやや独立したものと見なされます。開始中括弧は、先頭と同じインデントレベルで、独自の行にあります。例えば:
// Allman brace style
function
foo
(
x
,
y
,
z
)
{
if
(
x
)
{
a
();
}
else
{
b
();
c
();
}
}
ここでは、ブロックはステートメントのヘッダーとより密接に関連付けられています。同じ行のヘッダーの後に開始します。制御フローステートメントの本体は、単一のステートメントしかない場合でも、常に中括弧で囲みます。例えば:
// One True Brace Style
function
foo
(
x
,
y
,
z
)
{
if
(
x
)
{
a
();
}
else
{
b
();
c
();
}
}
1TBSは、(古い) K&R (Kernighan and Ritchie) スタイルの変種です。[21] K&Rスタイルでは、関数はAllmanスタイルで記述され、単一ステートメントのthen
ケースなど、必要のない場合は中括弧が省略されます。
// K&R brace style
function
foo
(
x
,
y
,
z
)
{
if
(
x
)
a
();
else
{
b
();
c
();
}
}
JavaScriptの世界でのデファクトスタンダードは1TBSです。Javaから継承されており、ほとんどのスタイルガイドで推奨されています。その理由の1つは客観的なものです。オブジェクトリテラルを返す場合は、キーワードreturn
と同じ行に開始中括弧を配置する必要があります (そうでない場合、自動セミコロン挿入はreturn
の後にセミコロンを挿入し、何も返されないことを意味します。落とし穴: ASIは予期せずステートメントを中断する可能性がありますを参照)。
return
{
name
:
'Jane'
};
明らかに、オブジェクトリテラルはコードブロックではありませんが、両方のフォーマットが同じであれば、物事はより一貫性があり、ミスをする可能性が低くなります。
私の個人的なスタイルと好みは
例外として、ステートメントを1行で記述できる場合は中括弧を省略します。例えば
if
(
x
)
return
x
;
リテラルによっても作成できるオブジェクトを生成するコンストラクターがいくつかあります。後者の方が通常は良い選択です。
var
obj
=
new
Object
();
// no
var
obj
=
{};
// yes
var
arr
=
new
Array
();
// no
var
arr
=
[];
// yes
var
regex
=
new
RegExp
(
'abc'
);
// avoid if possible
var
regex
=
/abc/
;
// yes
コンストラクターArray
を使用して、指定された要素を持つ配列を作成しないでください。要素で配列を初期化する (避ける!)で、その理由を説明しています。
var
arr
=
new
Array
(
'a'
,
'b'
,
'c'
);
// never ever
var
arr
=
[
'a'
,
'b'
,
'c'
];
// yes
このセクションでは、推奨されない賢さの例を収集しています。
// Don’t:
return
x
===
0
?
'red'
:
x
===
1
?
'green'
:
'blue'
;
// Better:
if
(
x
===
0
)
{
return
'red'
;
}
else
if
(
x
===
1
)
{
return
'green'
;
}
else
{
return
'blue'
;
}
// Best:
switch
(
x
)
{
case
0
:
return
'red'
;
case
1
:
return
'green'
;
default
:
return
'blue'
;
}
論理演算子を使用してif
ステートメントを省略しないでください:
foo
&&
bar
();
// no
if
(
foo
)
bar
();
// yes
foo
||
bar
();
// no
if
(
!
foo
)
bar
();
// yes
可能であれば、インクリメント演算子 (++
) とデクリメント演算子 (--
) をステートメントとして使用します。式として使用しないでください。後者の場合、それらは値を返しますが、ニーモニックはありますが、何が起こっているのかを理解するために考える必要があります。
// Unsure: what is happening?
return
++
foo
;
// Easy to understand
++
foo
;
return
foo
;
if
(
x
===
void
0
)
x
=
0
;
// not necessary in ES5
if
(
x
===
undefined
)
x
=
0
;
// preferable
ECMAScript 5以降、2番目の確認方法の方が優れています。undefinedの変更で、その理由を説明しています。
return
x
>>
0
;
// no
return
Math
.
round
(
x
);
// yes
シフト演算子を使用して、数値を整数に変換できます。ただし、通常は、Math.round()
などのより明示的な代替手段を使用する方が適切です。整数への変換では、整数への変換のすべての方法の概要を説明しています。
JavaScriptでは、賢さが確立されたパターンになっている場合は、賢くすることができます。
Or (||
) 演算子を使用してデフォルト値を提供することは、一般的なパターンです。たとえば、パラメーターの場合:
function
f
(
x
)
{
x
=
x
||
0
;
...
}
詳細とその他の例については、パターン: デフォルト値の提供を参照してください。
メソッドを汎用的に使用する場合は、Object.prototype
を {}
と省略できます。次の2つの式は同等です。
Object
.
prototype
.
hasOwnProperty
.
call
(
obj
,
propKey
)
{}.
hasOwnProperty
.
call
(
obj
,
propKey
)
また、Array.prototype
は []
と省略できます。
Array
.
prototype
.
slice
.
call
(
arguments
)
[].
slice
.
call
(
arguments
)
この件については、私は賛否両論です。これはハックです(インスタンスを介してプロトタイププロパティにアクセスしています)。しかし、コードがすっきりし、将来的にはエンジンがこのパターンを最適化すると予想しています。
ECMAScript 5 では、オブジェクトリテラル内のトレーリングカンマが有効です。
var
obj
=
{
first
:
'Jane'
,
last
:
'Doe'
,
// legal: trailing comma
};
ECMAScript 5 では、予約語(new
など)をプロパティキーとして使用することもできます。
> var obj = { new: 'abc' }; > obj.new 'abc'
私が好む、もう少し議論の余地のある規約をいくつか見てみましょう。
構文規則から始めます。
私は比較的タイトな空白が好きです。モデルは英語の書き方に倣います。開き括弧の後と閉じ括弧の前にはスペースを入れず、カンマの後にはスペースを入れます。
var
result
=
foo
(
'a'
,
'b'
);
var
arr
=
[
1
,
2
,
3
];
if
(
flag
)
{
...
}
無名関数の場合、Douglas Crockford のルールに従って、キーワード function
の後にスペースを入れます。その理由は、名前付き関数式から名前を削除した場合と同じ見た目になるためです。
function
foo
(
arg
)
{
...
}
// named function expression
function
(
arg
)
{
...
}
// anonymous function expression
演算子のスコープがわかりやすくなるため、読みやすくなります。
return
result
?
result
:
theDefault
;
// no
return
(
result
?
result
:
theDefault
);
// yes
次に、変数の規則について説明します。
// no
var
foo
=
3
,
bar
=
2
,
baz
;
// yes
var
foo
=
3
;
var
bar
=
2
;
var
baz
;
このアプローチの利点は、行の削除、挿入、並べ替えが簡単になり、行が自動的に正しくインデントされることです。
var
宣言がブロックスコープであるかのように扱うことができます。つまり、変数を使用するコンテキスト(ループ内、then
ブロックまたは else
ブロック内など)で変数を宣言できます。この種のローカルカプセル化により、コードフラグメントを個別に理解しやすくなります。また、コードフラグメントを削除したり、他の場所に移動したりすることも容易になります。前のルールの補足として、同じ変数を2つの異なるブロックで2回宣言しないでください。例えば
// Don’t do this
if
(
v
)
{
var
x
=
v
;
}
else
{
var
x
=
10
;
}
doSomethingWith
(
x
);
上記のコードは、次のコードと同じ効果と意図を持っているため、そのように記述する必要があります。
var
x
;
if
(
v
)
{
x
=
v
;
}
else
{
x
=
10
;
}
doSomethingWith
(
x
);
次に、オブジェクト指向に関する規則について説明します。
以下のことをお勧めします。
new
を使用する。そうする主な利点は次のとおりです。
コンストラクターの場合、厳格モードを使用することが重要です。これは、インスタンス化のために new
演算子を忘れることから保護するためです。また、コンストラクターで任意のオブジェクトを返すことができることに注意してください。コンストラクターの使用に関するその他のヒントは、コンストラクター実装のヒントに記載されています。
括弧を付けた方が、このようなコンストラクターの呼び出しが見やすくなると感じています。
var
foo
=
new
Foo
;
// no
var
foo
=
new
Foo
();
// yes
2つの演算子が互いに競合しないように括弧を使用してください。結果は必ずしも期待どおりにならない場合があります。
> false && true || true true > false && (true || true) false > (false && true) || true true
instanceof
は特に注意が必要です。
> ! {} instanceof Array false > (!{}) instanceof Array false > !({} instanceof Array) true
ただし、コンストラクターの後のメソッド呼び出しには問題がないと考えています。
new
Foo
().
bar
().
baz
();
// ok
(
new
Foo
()).
bar
().
baz
();
// not necessary
このセクションでは、さまざまなヒントを紹介します。
Boolean
、Number
、String()
、Object()
(関数として使用—これらの関数をコンストラクターとして使用しないでください)を介して値を型に変換します。その理由は、この規則の方が説明的であるためです。
> +'123' // no 123 > Number('123') // yes 123 > ''+true // no 'true' > String(true) // yes 'true'
this
を使用しない// Avoid:
function
handler
()
{
this
.
logError
(...);
}
// Prefer:
function
handler
(
context
)
{
context
.
logError
(...);
}
in
および hasOwnProperty
を使用してプロパティの存在を確認します( プロパティの反復と検出を参照)。これは、undefined
と比較したり、truthiness を確認したりするよりも、わかりやすく安全です。
// All properties:
if
(
obj
.
foo
)
// no
if
(
obj
.
foo
!==
undefined
)
// no
if
(
'foo'
in
obj
)
...
// yes
// Own properties:
if
(
obj
.
hasOwnProperty
(
'foo'
))
...
// risky for arbitrary objects
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
obj
,
'foo'
))
...
// safe
スタイルの問題を検討する場合は、常に次の質問をしてください。コードを理解しやすくするにはどうすればよいですか?賢くあろうとする誘惑に抵抗し、機械的な賢さのほとんどを JavaScript エンジンとミニファイアーに任せましょう(第32章を参照)。