- forEach は避けてください。
- パラメータ数の制限
- DOMイベントを処理するクラスは避けてください。
- 要素コンテナをコンストラクタに渡します。
- ParseInt を使用します。
- CSS セレクタ - プレフィックス
js-
を使用します。 - ESモジュールの構文
- モジュールの絶対パスと相対パス
- ページ以外のモジュールでは
DOMContentLoaded
を使用しないでください。 - XSSを回避
- 単一行の条件文は避けてください
- ESLint
- IIFE
- グローバル名前空間
- 副作用
- 純粋関数とデータ変異
JavaScriptスタイルガイド
私たちはAirbnbのJavaScriptスタイルガイドとそれに付随するリンターを使用して、JavaScriptスタイルガイドラインのほとんどを管理しています。
Airbnbが定めるスタイルガイドラインに加え、以下のような特別なルールがあります。
ヒント:ローカルで eslint を実行するには、次のコマンドを実行します。
yarn eslint
forEach は避けてください。
データを変異させるときはforEachを避けてください。 データを変異させるときはforEach
の代わりにmap
、reduce
、またはfilter
を使用してください。 これにより関数内の変異を最小限に抑えることができ、Airbnbのスタイルガイドに沿うようになります。
// bad
users.forEach((user, index) => {
user.id = index;
});
// good
const usersWithId = users.map((user, index) => {
return Object.assign({}, user, { id: index });
});
パラメータ数の制限
関数やメソッドに3つ以上のパラメータがある場合は、代わりにオブジェクトをパラメータとして使用します。
// bad
function a(p1, p2, p3) {
// ...
};
// good
function a(p) {
// ...
};
DOMイベントを処理するクラスは避けてください。
クラスの目的が DOM イベントをバインドしてコールバックを処理することだけであれば、関数を使用するほうがよいでしょう。
// bad
class myClass {
constructor(config) {
this.config = config;
}
init() {
document.addEventListener('click', () => {});
}
}
// good
const myFunction = () => {
document.addEventListener('click', () => {
// handle callback here
});
}
要素コンテナをコンストラクタに渡します。
クラスが DOM を操作する際には、 要素コンテナをパラメータとして受け取ります。 このほうがメンテナーでパフォーマンスも高くなります。
// bad
class a {
constructor() {
document.querySelector('.b');
}
}
// good
class a {
constructor(options) {
options.container.querySelector('.b');
}
}
ParseInt を使用します。
数値文字列を数値に変換する場合は、ParseInt
を使用します。
// bad
Number('10')
// good
parseInt('10', 10);
CSS セレクタ - プレフィックスjs-
を使用します。
CSSクラスがJavaScriptで要素への参照としてのみ使用される場合は、クラス名の前にjs-
.
// bad
<button class="add-user"></button>
// good
<button class="js-add-user"></button>
ESモジュールの構文
モジュールをインポートするには、ESモジュール構文を使用します:
// bad
const SomeClass = require('some_class');
// good
import SomeClass from 'some_class';
// bad
module.exports = SomeClass;
// good
export default SomeClass;
注: scripts/
とconfig/
のファイルではrequire
を使用しています。
モジュールの絶対パスと相対パス
インポートするモジュールが2階層以下の場合は、相対パスを使用してください。
// bad
import GitLabStyleGuide from '~/guides/GitLabStyleGuide';
// good
import GitLabStyleGuide from '../GitLabStyleGuide';
インポートするモジュールが2つ以上上のレベルにある場合は、代わりに絶対パスを使用してください:
// bad
import GitLabStyleGuide from '../../../guides/GitLabStyleGuide';
// good
import GitLabStyleGuide from '~/GitLabStyleGuide';
また、グローバル名前空間に追加しないでください。
ページ以外のモジュールではDOMContentLoaded
を使用しないでください。
インポートされたモジュールは、ロードされるたびに同じ動作をする必要があります。DOMContentLoaded
イベントは、/pages/*
ディレクトリにロードされたモジュールに対してのみ許可されます。これらは webpack で動的にロードされるからです。
XSSを回避
innerHTML
、append()
、html()
を使ってコンテンツを設定しないでください。脆弱性を開きすぎてしまいます。
単一行の条件文は避けてください
インデント(字下げ)は、ブランチやループ、リターン・ポイントの存在を素早く示すため、コードをスキャンする際に重要です。 これにより、制御フローを素早く理解することができます。
// bad
if (isThingNull) return '';
if (isThingNull)
return '';
// good
if (isThingNull) {
return '';
}
ESLint
ESLintの動作はツールガイドに記載されています。
IIFE
IIFE (Immediately-Invoked Function Expressions)の使用は避けてください。 IIFEでファイルの内容をラップしている例はたくさんありますが、Sprocketsからwebpackへの移行後は、もはや必要ありません。 これ以上IIFEを使用せず、レガシーコードをリファクタリングする際は自由に削除してください。
グローバル名前空間
グローバル・ネームスペースへの追加は避けてください。
// bad
window.MyClass = class { /* ... */ };
// good
export default class MyClass { /* ... */ }
副作用
トップレベルの副作用
export
を含むスクリプトでは、トップレベルの副作用は禁止されています:
// bad
export default class MyClass { /* ... */ }
document.addEventListener("DOMContentLoaded", function(event) {
new MyClass();
}
コンストラクタでの副作用の回避
constructor
内で非同期コールや API リクエスト、DOM 操作を行わないようにしましょう。 そうすることで、テストが書きやすくなり、単一責任の原則 (Single Responsibility Principle)に反することもなくなります。
// bad
class myClass {
constructor(config) {
this.config = config;
axios.get(this.config.endpoint)
}
}
// good
class myClass {
constructor(config) {
this.config = config;
}
makeRequest() {
axios.get(this.config.endpoint)
}
}
const instance = new myClass();
instance.makeRequest();
純粋関数とデータ変異
小さな純粋な関数をたくさん書き、突然変異が起こる場所を最小限にするよう努力します。
// bad
const values = {foo: 1};
function impureFunction(items) {
const bar = 1;
items.foo = items.a * bar + 2;
return items.a;
}
const c = impureFunction(values);
// good
var values = {foo: 1};
function pureFunction (foo) {
var bar = 1;
foo = foo * bar + 2;
return foo;
}
var c = pureFunction(values.foo);