プログラミングスタイル
概要
「プログラミングスタイル」とは、コードを記述するためのスタイル規則を指します。プログラマーが異なれば、プログラミング スタイルも異なることがよくあります。
コンパイラの仕様はプログラマが遵守しなければならない「文法規則」と呼ばれ、コンパイラが無視する部分はプログラマが自由に選択できる「プログラミングスタイル」と呼ばれるという人もいます。この記述は完全に正しいわけではありませんが、プログラマーはプログラミング スタイルを自由に選択できますが、適切なプログラミング スタイルは、高品質でエラーが少なく、メンテナンスが容易なプログラムを作成するのに役立ちます。
したがって、プログラミング スタイルの選択は、個人の好み、慣れ、入力量、その他の要因に基づいて行うべきではなく、コードを明確で読みやすくし、エラーを減らす方法を考慮する必要があります。自分の好みのスタイルではなく、自分の意図を明確に表現できるスタイルを選択します。これは、文法上の自由度が高い JavaScript のような言語では特に重要です。
心に留めておかなければならないことの 1 つは、「プログラミング スタイル」を選択した場合は、それに固執し、スタイルを混合しないようにする必要があるということです。他の人のプロジェクトに参加する場合は、既存のスタイルに固執する必要があります。
インデント
行頭のスペースと Tab キーの両方で、コードのインデント効果 (インデント) を生成できます。
Tab キーはキーストロークを節約できますが、テキスト エディタによって Tab の表示方法が異なるため、スペース バーを使用すると表示効果がより均一になると考える人もいます。
どちらの方法を選択しても、常にこの選択に固執する必要があります。ある瞬間には Tab キーを使用し、次の瞬間にはスペースバーを使用しないでください。
ブロック
ループと判定のコード本体が 1 行のみの場合、JavaScript ではブロックで中括弧を省略できます。
もし(a)
b();
c();
上記コードの本来の意味は以下のようなものと考えられます。
if (a) {
b();
c();
}
ただし、実際の効果は以下の通りです。
if (a) {
b();
}
c();
したがって、ブロックを表すには常に中括弧を使用することをお勧めします。
さらに、ブロックの先頭の中括弧の位置を記述するさまざまな方法があります。最も一般的な方法は 2 つあり、1 つは左中括弧で新しい行を開始する方法です。
ブロック
{
// ...
}
もう 1 つは、キーワードの後に左中括弧が続くことです。
ブロック {
// ...
}
一般に、どちらの記述方法も使用できます。ただし、JavaScript では文末にセミコロンが自動的に追加され、微妙なエラーが発生するため、JavaScript では後者の方法が使用されます。
戻る
{
キー: 値
};
// と同等
戻る;
{
キー: 値
};
上記のコードの本来の目的はオブジェクトを返すことですが、JavaScript が return
ステートメントの後に自動的にセミコロンを追加するため、実際には unknown
が返されます。この種のエラーを回避するには、次のように記述する必要があります。
戻る {
キー:値
};
したがって、ブロックの始まりを示す中括弧は新しい行で始めるべきではありません。
括弧
JavaScript では括弧には 2 つの関数があり、1 つは関数呼び出しを表し、もう 1 つは式のグループ化を表します。
// 括弧は関数呼び出しを示します
console.log('abc');
// 括弧は式の組み合わせを表します
(1 + 2) * 3
これら 2 つの異なる括弧を区別するにはスペースを使用することをお勧めします。
関数が呼び出されるときに、関数名と左括弧の間にスペースがないことを示します。
関数定義を示す場合、関数名と左括弧の間にスペースは入れません。
他の場合には、前の構文要素と左括弧の間にスペースがあります。
上記のルールに従えば、以下の書き方は変則的となります。
フー(バー)
戻り値(a+b);
if(a === 0) {...}
関数 foo (b) {...}
関数(x) {...}
上記のコードの最後の行は匿名関数であり、「function」は関数名ではなく構文キーワードであるため、左括弧との間にスペースを入れる必要があります。
行末のセミコロン
セミコロンはステートメントの終わりを示します。 JavaScript では、行末のセミコロンを省略できます。実際、開発者の中には行末にセミコロンを決して書かない人もいます。ただし、以下で説明する理由により、このセミコロンを省略しないことをお勧めします。
セミコロンなし
まず、以下の3つの場合は文法上、最後にセミコロンを付ける必要はないと規定されています。
(1) for および while ループ
のために ( ; ; ) {
} // セミコロンなし
while (true) {
} // セミコロンなし
do...while
ループにはセミコロンがあることに注意してください。
する {
ああ、
} while(a > 0) // セミコロンは省略できません
(2) 分岐文: if、switch、try
if (true) {
} // セミコロンなし
スイッチ() {
} // セミコロンなし
試す {
} キャッチ {
} // セミコロンなし
(3) 関数の宣言文
関数 f() {
} // セミコロンなし
関数式では引き続きセミコロンが使用されることに注意してください。
var f = 関数 f() {
};
上記 3 つの場合、セミコロンを使用するとエラーは発生しません。解釈エンジンはこのセミコロンを空のステートメントとして解釈するためです。
セミコロンの自動追加
前のセクションの 3 つの場合を除き、すべてのステートメントでセミコロンを使用する必要があります。ただし、セミコロンが使用されていない場合、ほとんどの場合、JavaScript によって自動的に追加されます。
変数 a = 1
// と同等
変数 a = 1;
この文法上の機能は、自動セミコロン挿入 (ASI) と呼ばれます。
したがって、文末のセミコロンを省略することを主張する人もいます。問題は、次の行の先頭が現在の行の末尾と連結して解釈できる場合、JavaScript は自動的にセミコロンを追加しないことです。
// var a = 3 と同等
変数
ある
=
3
// 'abc'.length と同等
「ABC」
。長さ
// a + b を返すのと同じです。
+ を返す
b;
// obj.foo(arg1, arg2); と同等です。
obj.foo(arg1,
引数2);
// 3 * 2 + 10 * (27 / 6) に相当
3*2
+
10* (27 / 6)
上記のコードは複数行に分けて説明しますが、各行にセミコロンは自動的に付加されません。これらの例は比較的分かりやすいですが、次の例はそれほど簡単ではありません。
x = y
(関数 () {
// ...
})();
// と同等
x = y(関数() {...})();
セミコロンが自動的に追加されない例をさらにいくつか示します。
// エンジンはこれを c(d+e) として解釈します
変数 a = b + c
(d+e).toString();
// エンジンはこれを a = b/hi/g.exec(c).map(d) として解釈します
// 正規表現内のスラッシュは除算演算子として使用されます
a = b
/hi/g.exec(c).map(d);
// 'b'['red', 'green'], として解釈されます
// つまり、文字列を配列として扱い、インデックスによって値を取得します
var a = 'b'
['赤', '緑'].forEach(関数 (c) {
コンソール.ログ(c);
})
// function (x) { return x }(a++) として解釈されます
// つまり、無名関数が呼び出され、結果 f は 0 に等しくなります。
変数 a = 0;
var f = function (x) { return x }
(a++)
JavaScript エンジンは、次の行の先頭と現在の行の末尾を一緒に解釈できない場合にのみ、自動的にセミコロンを追加します。
if (a < 0) a = 0
コンソール.ログ(a)
// 次のコードと同等です。
// 0consoleには意味がないので
if (a < 0) a = 0;
コンソール.ログ(a)
さらに、行が「インクリメント」 (++
) または「デクリメント」 (--
) 演算子で始まる場合、それらの前にセミコロンが自動的に追加されます。
a = b = c = 1
ある
++
b
--
c
console.log(a, b, c)
// 1 2 0
上記のコードが 1 2 0
の結果を取得する理由は、インクリメント演算子とデクリメント演算子の前にセミコロンが自動的に追加されるためです。上記のコードは実際には次の形式と同等です。
a = b = c = 1;
a;
++b;
--c;
Continue
、break
、return
、throw
の 4 つのステートメントの直後に改行文字が続く場合、セミコロンが自動的に追加されます。これは、「return」ステートメントがオブジェクト リテラルを返す場合、左中括弧を同じ行に書かなければならず、そうしないと期待した結果が得られないことを意味します。
戻る
{ 最初: 'ジェーン' };
// 次のように解釈されます
戻る;
{ 最初: 'ジェーン' };
セミコロンを追加する解釈エンジンの自動動作は予測できないため、行末のセミコロンを省略するコードを作成しないでください。
末尾のセミコロンを省略すべきではないもう 1 つの理由があります。一部の JavaScript コード コンプレッサー (uglifier) はセミコロンを自動的に追加しないため、セミコロンのない末尾に遭遇すると、コードを 1 行に圧縮せずにそのままにし、圧縮で最適な結果を得ることができなくなります。
さらに、末尾のセミコロンを記述しないと、スクリプトのマージ エラーが発生する可能性があります。したがって、一部のコード ライブラリでは、ステートメントの最初の行の前にセミコロンが追加されます。
;var a = 1;
// ...
上記の書き方により、他のスクリプトとマージする際に、前のスクリプトの最終行にセミコロンが無くエラーになる問題を回避できます。
グローバル変数
おそらく JavaScript の文法上の最大の欠点は、グローバル変数がどのコード ブロックでも読み取りおよび書き込み可能であることです。これはコードのモジュール化と再利用にとって非常に有害です。
したがって、グローバル変数の使用は避けることをお勧めします。これを使用する必要がある場合は、変数名を表すために大文字を使用することを検討してください。これにより、グローバル変数であることがわかりやすくなります (「UPPER_CASE」など)。
変数宣言
JavaScript は、変数宣言をブロックの先頭に自動的に「ホイスト」します。
if (!x) {
var x = {};
}
// と同等
変数x;
if (!x) {
x = {};
}
これは、変数 x
が if
ブロックの前に存在することを意味します。起こり得る問題を回避するには、コード ブロックの先頭に変数宣言を配置するのが最善です。
for (var i = 0; i < 10; i++) {
// ...
}
// のように書かれます
変数 i;
for (i = 0; i < 10; i++) {
// ...
}
上記の書き方だと、グローバルループ変数「i」があることが分かります。
さらに、すべての関数は使用前に定義する必要があります。関数内の変数宣言は関数の先頭に置く必要があります。
ステートメント付き
「with」を使用するとコードの記述を減らすことができますが、混乱を引き起こす可能性があります。
(お) {
foo = バー;
}
上記のコードでは、次の 4 つの実行結果が得られます。
o.foo = バー;
o.foo = o.bar;
foo = バー;
foo = o.bar;
異なる変数が定義されているかどうかに応じて、4 つの結果すべてが発生する可能性があります。したがって、「with」ステートメントは使用しないでください。
##平等と厳密な平等
JavaScript には、等価性を表す 2 つの演算子があります。「等価性」 (==
) と「厳密な等価性」 (===
) です。
等価演算子は変数の型を自動的に変換するため、多くの予期しない状況が発生します。
0 == ''// true
1 == true // true
2 == true // false
0 == '0' // 真
false == 'false' // false
false == '0' // true
' \t\r\n ' == 0 // true
したがって、等価演算子 (==
) は使用せず、厳密な等価演算子 (===
) のみを使用することをお勧めします。
ステートメントの組み合わせ
プログラマの中には、シンプルさを追求し、さまざまな目的のステートメントを組み合わせるのを好む人もいます。たとえば、元のステートメントは次のとおりです
a = b;
if (a) {
// ...
}
彼はこのようなことを書くのが好きです。
if (a = b) {
// ...
}
1 行欠落していますが、可読性が大幅に低下し、この行のコードが次のことを意味していると他の人が誤解する可能性があります。
if (a === b) {
// ...
}
目的の異なるステートメントを 1 行に結合しないことをお勧めします。
インクリメント演算子とデクリメント演算子
自動インクリメント (++
) および自動デクリメント (--
) 演算子は、変数の前後に配置すると異なる値を返し、エラーが発生しやすくなります。実際、すべての ++
演算子は += 1
に置き換えることができます。
++x
// と同等
x += 1;
代わりに += 1
を使用すると、コードがより明確になります。
インクリメント (++
) 演算子とデクリメント (--
) 演算子の代わりに、+=
と -=
を使用することをお勧めします。
スイッチ...ケース構造
switch...case
構造では、各 case
の最後の行が break
ステートメントである必要があります。そうでない場合は、次の case
が実行されます。これは忘れられやすいだけでなく、コードが冗長になります。
さらに、switch...case
では中括弧が使用されていないため、コード形式の統一には役立ちません。さらに、この構造は goto
ステートメントに似ており、プログラム フローで混乱を引き起こしやすく、コード構造がわかりにくくなり、オブジェクト指向プログラミングの原則に準拠していません。
関数 doAction(アクション) {
スイッチ (アクション) {
ケース「ハック」:
「ハック」を返します。
「スラッシュ」の場合:
「スラッシュ」を返します。
ケース「実行」:
「実行」を返します。
デフォルト:
throw new Error('無効なアクションです。');
}
}
上記のコードをオブジェクト構造に書き直すことをお勧めします。
関数 doAction(アクション) {
var アクション = {
'ハック': 関数 () {
「ハック」を返します。
}、
'スラッシュ': 関数 () {
「スラッシュ」を返します。
}、
'実行': 関数 () {
「実行」を返します。
}
};
if (アクションの種類[アクション] !== '関数') {
throw new Error('無効なアクションです。');
}
アクションを返す[アクション]();
}
したがって、switch...case
構造をオブジェクト構造に置き換えることをお勧めします。
参考リンク
- Eric Elliott、JavaScript アプリケーションのプログラミング、第 2 章 JavaScript スタイル ガイド、オライリー、2014 年
- Axel Rauschmayer、JavaScript のメタ スタイル ガイド
- Axel Rauschmayer、JavaScript での自動セミコロン挿入
- Rod Vagg、JavaScript とセミコロン
作者: wangdoc
アドレス: https://wangdoc.com/
ライセンス: クリエイティブ・コモンズ 3.0