JavaScriptスタイルガイド

私たちはAirbnbのJavaScriptスタイルガイドとそれに付随するリンターを使用して、JavaScriptスタイルガイドラインのほとんどを管理しています。

Airbnbが定めるスタイルガイドラインに加え、以下のような特別なルールがあります。

ヒント:ローカルで eslint を実行するには、次のコマンドを実行します。yarn eslint

forEach は避けてください。

データを変異させるときはforEachを避けてください。 データを変異させるときはforEachの代わりにmapreduce 、または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を回避

innerHTMLappend()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);