JavaScriptへのほとんど合理的なアプローチ
注:このガイドでは、Babelを使用していることを前提としており、babel-preset-airbnbまたは同等のものを使用する必要があります。また、アプリに shims/polyfill を airbnb-browser-shim または同等のものと共にインストールしていることも前提としています。
このガイドは他の言語でも入手できます。翻訳を見る
その他のスタイルガイド
1.1 プリミティブ: プリミティブ型にアクセスするときは、その値を直接操作します。
string
number
boolean
null
undefined
symbol
bigint
const foo = 1;
let bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
1.2 複合型: 複合型にアクセスするときは、その値への参照を処理します。
object
array
function
const foo = [1, 2];
const bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
2.1すべての参照に使用します。の使用は避けてください。ESLINT: 優先定数
、非構成割り当て
const
var
なぜでしょうか。これにより、参照を再割り当てできなくなり、バグが発生したり、コードを理解しにくくなったりする可能性があります。
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
2.2 参照を再割り当てする必要がある場合は、 の代わりに を使用します。エスリント: 変数なし
let
var
なぜでしょうか。 は、 のように関数スコープではなくブロックスコープです。
letvar
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
2.3 と はどちらもブロックスコープであるのに対し、 は関数スコープであることに注意してください。
let
const
var
// const and let only exist in the blocks they are defined in.
{
let a = 1;
const b = 1;
var c = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError
console.log(c); // Prints 1
上記のコードでは、その参照を見ることができ、番号が含まれている間、ReferenceErrorを生成します。これは、 とがブロックスコープであり、 が包含関数にスコープされているためです。
a
b
c
a
b
c
3.1 オブジェクトの作成にリテラル構文を使用します。ESLINT: 新しいオブジェクトなし
// bad
const item = new Object();
// good
const item = {};
3.2 動的プロパティ名を持つオブジェクトを作成する場合は、計算プロパティ名を使用します。
なぜでしょうか。これにより、オブジェクトのすべてのプロパティを1か所で定義できます。
function getKey(k) {
return `a key named ${k}`;
}
// bad
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};
3.3オブジェクトメソッドの省略形を使用します。ESLINT: オブジェクト-省略形
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
3.4 プロパティ値の省略形を使用します。ESLINT: オブジェクト-省略形
なぜでしょうか。それは短くて説明的です。
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
3.5 オブジェクト宣言の先頭で短縮形プロパティをグループ化します。
なぜでしょうか。どのプロパティが短縮形を使用しているかを簡単に判断できます。
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
};
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};
3.6 無効な識別子であるプロパティのみを引用符で囲みます。エスリント:引用小道具
なぜでしょうか。一般的に、主観的に読みやすいと考えています。構文の強調表示が改善され、多くのJSエンジンによってより簡単に最適化されます。
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
3.7 、などのメソッドを直接呼び出さないESLINT:プロトタイプビルトインなし
Object.prototype
hasOwnProperty
propertyIsEnumerable
isPrototypeOf
なぜでしょうか。これらのメソッドは、問題のオブジェクトのプロパティによってシャドウされている可能性があります-考慮してください-または、オブジェクトはnullオブジェクト()である可能性があります。
{ hasOwnProperty: false }Object.create(null)
// bad
console.log(object.hasOwnProperty(key));
// good
console.log(Object.prototype.hasOwnProperty.call(object, key));
// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
console.log(has.call(object, key));
/* or */
import has from 'has'; // https://www.npmjs.com/package/has
console.log(has(object, key));
/* or */
console.log(Object.hasOwn(object, key)); // https://www.npmjs.com/package/object.hasown
3.8 Object.ssign
よりもオブジェクトスプレッド構文を優先して、浅いコピーオブジェクトにします。object rest パラメーター構文を使用して、特定のプロパティが省略された新しいオブジェクトを取得します。エスリント:優先オブジェクトスプレッド
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
4.1 配列の作成にはリテラル構文を使用します。ESLINT: 配列コンストラクタなし
// bad
const items = new Array();
// good
const items = [];
4.2 配列に項目を追加するには、直接代入の代わりに Array#push を使用します。
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
4.3 配列スプレッドを使用して配列をコピーする。
...
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i += 1) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
4.4 反復可能なオブジェクトを配列に変換するには、Array.from
の代わりにスプレッドを使用します。
...
const foo = document.querySelectorAll('.foo');
// good
const nodes = Array.from(foo);
// best
const nodes = [...foo];
4.5 配列のようなオブジェクトを配列に変換するには、Array.from
を使用します。
const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
// bad
const arr = Array.prototype.slice.call(arrLike);
// good
const arr = Array.from(arrLike);
4.6 イテラブルへのマッピングにはスプレッドの代わりに Array.from
を使用すると、中間配列の作成が回避されるためです。
...
// bad
const baz = [...foo].map(bar);
// good
const baz = Array.from(foo, bar);
4.7 配列メソッドのコールバックで return ステートメントを使用します。関数本体が副作用のない式を返す単一のステートメントで構成されている場合は、8.2以降、戻り値を省略してもかまいません。ESLint: 配列コールバックリターン
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => x + 1);
// bad - no returned value means `acc` becomes undefined after the first iteration
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
const flatten = acc.concat(item);
});
// good
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
const flatten = acc.concat(item);
return flatten;
});
// bad
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
} else {
return false;
}
});
// good
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
}
return false;
});
4.8配列に複数の行がある場合、配列の括弧を開いた後と閉じる前に改行を使用する
// bad
const arr = [
[0, 1], [2, 3], [4, 5],
];
const objectInArray = [{
id: 1,
}, {
id: 2,
}];
const numberInArray = [
1, 2,
];
// good
const arr = [[0, 1], [2, 3], [4, 5]];
const objectInArray = [
{
id: 1,
},
{
id: 2,
},
];
const numberInArray = [
1,
2,
];
5.1 オブジェクトの複数のプロパティにアクセスして使用する場合は、オブジェクトの破壊を使用します。エスリント:優先破壊
なぜでしょうか。破棄すると、これらのプロパティの一時的な参照を作成したり、オブジェクトに繰り返しアクセスしたりする必要がなくなります。オブジェクトアクセスを繰り返すと、より多くの反復的なコードが作成され、より多くの読み取りが必要になり、間違いの機会が増えます。オブジェクトを破棄すると、ブロック全体を読み取って何が使用されているかを判断する必要はなく、ブロックで使用されるオブジェクト構造の定義の単一のサイトも提供されます。
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
5.3配列の破壊ではなく、複数の戻り値に対してオブジェクトの破壊を使用します。
なぜでしょうか。時間の経過と共に新しいプロパティを追加したり、呼び出しサイトを中断することなく順序を変更したりできます。
// bad
function processInput(input) {
// then a miracle occurs
return [left, right, top, bottom];
}
// the caller needs to think about the order of return data
const [left, __, top] = processInput(input);
// good
function processInput(input) {
// then a miracle occurs
return { left, right, top, bottom };
}
// the caller selects only the data they need
const { left, top } = processInput(input);
6.1 文字列には一重引用符を使用します。エスリント:引用符
''
// bad
const name = "Capt. Janeway";
// bad - template literals should contain interpolation or newlines
const name = `Capt. Janeway`;
// good
const name = 'Capt. Janeway';
6.2 行が 100 文字を超える文字列は、文字列連結を使用して複数行にまたがって記述しないでください。
なぜでしょうか。壊れた文字列は操作が難しく、コードを検索しにくくします。
// bad
const errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';
// bad
const errorMessage = 'This is a super long error that was thrown because ' +
'of Batman. When you stop to think about how Batman had anything to do ' +
'with this, you would get nowhere fast.';
// good
const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
6.3 プログラムで文字列を作成する場合は、連結ではなくテンプレート文字列を使用します。eslint: 優先テンプレート
テンプレート中括弧間隔
なぜでしょうか。テンプレート文字列は、適切な改行と文字列補間機能を備えた読みやすく簡潔な構文を提供します。
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// bad
function sayHi(name) {
return `How are you, ${ name }?`;
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
6.5 文字列内の文字を不必要にエスケープしないでください。エスリント:役に立たない脱出
なぜでしょうか。バックスラッシュは読みやすさを損なうため、必要な場合にのみ存在する必要があります。
// bad
const foo = '\'this\' \i\s \"quoted\"';
// good
const foo = '\'this\' is "quoted"';
const foo = `my name is '${name}'`;
7.1 関数宣言の代わりに名前付き関数式を使用する。エスリント:ファンクスタイル
なぜでしょうか。関数宣言はホイストされているため、ファイルで定義する前に関数を参照するのは簡単です。これは、可読性と保守性を損ないます。関数の定義が大きく複雑で、ファイルの残りの部分の理解を妨げている場合は、おそらくそれを独自のモジュールに抽出する時が来ました!名前が包含変数から推論されるかどうかに関係なく、式に明示的に名前を付けることを忘れないでください(これは、最近のブラウザやBabelなどのコンパイラを使用する場合によく見られます)。これにより、エラーの呼び出し履歴に関する仮定が排除されます。(ディスカッション)
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};
7.2 すぐに呼び出された関数式を括弧で囲んで折り返します。エスリント:ラップIIFE
なぜでしょうか。すぐに呼び出される関数式は単一のユニットであり、両方をラップし、その呼び出しparensはparensでこれをきれいに表現します。モジュールがいたるところにある世界では、IIFEはほとんど必要ありません。
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
ループ機能なし
if
while
7.4 注: ECMA-262 では、a をステートメントのリストとして定義しています。関数宣言はステートメントではありません。
block
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
let test;
if (currentUser) {
test = () => {
console.log('Yup.');
};
}
7.5 パラメータに名前を付けないでください。これは、すべての関数スコープに与えられるオブジェクトよりも優先されます。
arguments
arguments
// bad
function foo(name, options, arguments) {
// ...
}
// good
function foo(name, options, args) {
// ...
}
7.6 使用しない 代わりに REST 構文を使用することを選択します。eslint: prefer-rest-params
arguments
...
なぜでしょうか。 は、どの引数をプルするかについて明示しています。さらに、残りの引数は実際の配列であり、単に配列のようなものではありません。
...arguments
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
7.7 関数の引数を変更するのではなく、デフォルトのパラメーター構文を使用します。
// really bad
function handleThings(opts) {
// No! We shouldn’t mutate function arguments.
// Double bad: if opts is falsy it'll be set to an object which may
// be what you want but it can introduce subtle bugs.
opts = opts || {};
// ...
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
7.8 デフォルトのパラメータで副作用を避ける。
なぜでしょうか。彼らは推論するのに混乱しています。
let b = 1;
// bad
function count(a = b++) {
console.log(a);
}
count(); // 1
count(); // 2
count(3); // 3
count(); // 3
7.9 デフォルトのパラメータは常に最後にします。eslint: default-param-last
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
7.10 Function コンストラクタを使用して新しい関数を作成しないでください。ESLINT: no-new-func
なぜでしょうか。この方法で関数を作成すると、脆弱性を開く と同様に文字列が評価されます。
eval()
// bad
const add = new Function('a', 'b', 'return a + b');
// still bad
const subtract = Function('a', 'b', 'return a - b');
7.11 関数シグネチャの間隔。ESLINT: スペース・ビフォア・ファンクション・パレン・スペース・
ビフォア・ブロック
なぜでしょうか。一貫性は良好であり、名前を追加または削除するときにスペースを追加または削除する必要はありません。
// bad
const f = function(){};
const g = function (){};
const h = function() {};
// good
const x = function () {};
const y = function a() {};
7.12 パラメータを変更しないでください。ESLINT: パラメータ再割り当てなし
なぜでしょうか。パラメーターとして渡されたオブジェクトを操作すると、最初の呼び出し元で不要な変数の副作用が発生する可能性があります。
// bad
function f1(obj) {
obj.key = 1;
}
// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
}
7.13 パラメータを再割り当てしない。ESLINT: パラメータ再割り当てなし
なぜでしょうか。パラメーターを再割り当てすると、特にオブジェクトにアクセスするときに予期しない動作が発生する可能性があります。また、特にV8では最適化の問題が発生する可能性があります。
arguments
// bad
function f1(a) {
a = 1;
// ...
}
function f2(a) {
if (!a) { a = 1; }
// ...
}
// good
function f3(a) {
const b = a || 1;
// ...
}
function f4(a = 1) {
// ...
}
7.14 可変個引数関数を呼び出すためにスプレッド構文の使用を優先します。エスリント:優先スプレッド
...
なぜでしょうか。それはよりクリーンです、あなたは文脈を提供する必要はありません、そしてあなたは簡単に作曲することはできません。
newapply
// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);
// good
const x = [1, 2, 3, 4, 5];
console.log(...x);
// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
// good
new Date(...[2016, 8, 5]);
7.15 複数行のシグネチャまたは呼び出しを持つ関数は、このガイドの他のすべての複数行リストと同様に、各項目を単独で行に、最後の項目に末尾のコンマを付けてインデントする必要があります。ESLINT: 関数-括弧 - 改行
// bad
function foo(bar,
baz,
quux) {
// ...
}
// good
function foo(
bar,
baz,
quux,
) {
// ...
}
// bad
console.log(foo,
bar,
baz);
// good
console.log(
foo,
bar,
baz,
);
8.1 (インラインコールバックを渡すときなど) 匿名関数を使用する必要がある場合は、矢印関数表記を使用します。ESLINT:優先矢印コールバック
、矢印間隔
なぜでしょうか。これは、 のコンテキストで実行される関数のバージョンを作成します。これは通常、必要なものであり、より簡潔な構文です。
this
なぜ駄目なのですか。かなり複雑な関数がある場合は、そのロジックを独自の名前付き関数式に移動することができます。
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
8.2 関数本体が副作用のない式を返す単一のステートメントで構成されている場合は、中括弧を省略して暗黙の戻り値を使用します。それ以外の場合は、中括弧を保持し、ステートメントを使用します。エスリント:アローパレンス
、アローボディスタイル
return
なぜでしょうか。構文上の砂糖。複数の関数が連鎖しているときによく読みます。
// bad
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map((number) => `A string containing the ${number + 1}.`);
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map((number, index) => ({
[index]: number,
}));
// No implicit return with side effects
function foo(callback) {
const val = callback();
if (val === true) {
// Do something if callback returns true
}
}
let bool = false;
// bad
foo(() => bool = true);
// good
foo(() => {
bool = true;
});
8.3 式が複数行にまたがる場合は、読みやすくするために括弧で囲みます。
なぜでしょうか。関数の開始位置と終了位置を明確に示します。
// bad
['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod,
)
);
// good
['get', 'post', 'put'].map((httpMethod) => (
Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod,
)
));
8.4 明確さと一貫性を保つために、引数を必ず括弧で囲みます。エスリント:矢印括弧
なぜでしょうか。引数を追加または削除するときの差分チャーンを最小限に抑えます。
// bad
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map((x) => x * x);
// bad
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));
// good
[1, 2, 3].map((number) => (
`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));
// bad
[1, 2, 3].map(x => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
8.5 矢印関数の構文 () と比較演算子 (, ) を混同しないようにします。エスリント:紛らわしい矢印
=>
<=
>=
// bad
const itemHeight = (item) => item.height <= 256 ? item.largeSize : item.smallSize;
// bad
const itemHeight = (item) => item.height >= 256 ? item.largeSize : item.smallSize;
// good
const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize);
// good
const itemHeight = (item) => {
const { height, largeSize, smallSize } = item;
return height <= 256 ? largeSize : smallSize;
};
8.6 暗黙の戻り値を持つ矢印関数本体の位置を強制します。エスリント:暗黙の矢印改行
// bad
(foo) =>
bar;
(foo) =>
(bar);
// good
(foo) => bar;
(foo) => (bar);
(foo) => (
bar
)
9.1 常に .直接操作することは避けてください。
class
prototype
なぜでしょうか。 構文はより簡潔で、推論が容易です。
class
// bad
function Queue(contents = []) {
this.queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
};
// good
class Queue {
constructor(contents = []) {
this.queue = [...contents];
}
pop() {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
}
}
9.2 継承に使用します。
extends
なぜでしょうか。これは、 を壊すことなくプロトタイプ機能を継承するための組み込みの方法です。
instanceof
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this.queue[0];
};
// good
class PeekableQueue extends Queue {
peek() {
return this.queue[0];
}
}
9.3 メソッドはメソッドチェーンのヘルプに戻ることができます。
this
// bad
Jedi.prototype.jump = function () {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function (height) {
this.height = height;
};
const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined
// good
class Jedi {
jump() {
this.jumping = true;
return this;
}
setHeight(height) {
this.height = height;
return this;
}
}
const luke = new Jedi();
luke.jump()
.setHeight(20);
9.4 カスタムメソッドを書いても大丈夫ですが、それが正常に動作し、副作用を引き起こさないことを確認してください。
toString()
class Jedi {
constructor(options = {}) {
this.name = options.name || 'no name';
}
getName() {
return this.name;
}
toString() {
return `Jedi - ${this.getName()}`;
}
}
9.5 クラスにはデフォルトのコンストラクタが指定されていない場合、デフォルトのコンストラクタがあります。空のコンストラクター関数や、親クラスにデリゲートするだけのコンストラクター関数は不要です。eslint: 役に立たないコンストラクタ
// bad
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// bad
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
9.6 クラスメンバーの重複を避ける。エスリント:重複禁止クラスのメンバー
なぜでしょうか。重複するクラスメンバー宣言は、最後の宣言を暗黙のうちに優先します - 重複を持つことはほぼ確実にバグです。
// bad
class Foo {
bar() { return 1; }
bar() { return 2; }
}
// good
class Foo {
bar() { return 1; }
}
// good
class Foo {
bar() { return 2; }
}
9.7 クラスメソッドは、外部ライブラリまたはフレームワークが特定の非静的メソッドを使用する必要がない限り、静的メソッドを使用するか、静的メソッドにする必要があります。インスタンスメソッドであることは、受信者のプロパティに基づいて異なる動作をすることを示す必要があります。eslint: class-methods-use-this
this
// bad
class Foo {
bar() {
console.log('bar');
}
}
// good - this is used
class Foo {
bar() {
console.log(this.bar);
}
}
// good - constructor is exempt
class Foo {
constructor() {
// ...
}
}
// good - static methods aren't expected to use this
class Foo {
static bar() {
console.log('bar');
}
}
10.1 非標準のモジュール システムでは、常にモジュール (/) を使用してください。いつでもお好みのモジュールシステムにトランスパイルできます。
import
export
なぜでしょうか。モジュールは未来です、今未来を使い始めましょう。
// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
10.2 ワイルドカード インポートを使用しない。
なぜでしょうか。これにより、デフォルトのエクスポートが 1 つになります。
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
10.3 また、インポートから直接エクスポートしないでください。
なぜでしょうか。ワンライナーは簡潔ですが、インポートする明確な方法とエクスポートする明確な方法が1つあると、一貫性が保たれます。
// bad
// filename es6.js
export { es6 as default } from './AirbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
10.4 1 か所のパスからのみインポートします。
エスリント:重複インポートなし
なぜでしょうか。同じパスからインポートする複数の行があると、コードの保守が難しくなる可能性があります。
// bad
import foo from 'foo';
// … some other imports … //
import { named1, named2 } from 'foo';
// good
import foo, { named1, named2 } from 'foo';
// good
import foo, {
named1,
named2,
} from 'foo';
10.5 変更可能なバインディングをエクスポートしないでください。
ESLINT: インポート/変更不可能なエクスポート
なぜでしょうか。一般的には変更を避ける必要がありますが、特に可変バインディングをエクスポートする場合は避けてください。この手法は特殊なケースで必要になる場合がありますが、一般的には定数参照のみをエクスポートする必要があります。
// bad
let foo = 3;
export { foo };
// good
const foo = 3;
export { foo };
10.6 エクスポートが 1 つのモジュールでは、名前付きエクスポートよりもデフォルトのエクスポートを優先します。
ESLINT: インポート/優先デフォルト-エクスポート
なぜでしょうか。1つのものだけをエクスポートするファイルを増やすことを奨励するため、読みやすさと保守性が向上します。
// bad
export function foo() {}
// good
export default function foo() {}
10.7 すべての s を非インポートステートメントの上に置きます。
エスリント:インポート/最初
import
なぜでしょうか。は吊り上げられているので、すべてを一番上に保つと、驚くべき動作を防ぐことができます。
import
// bad
import foo from 'foo';
foo.init();
import bar from 'bar';
// good
import foo from 'foo';
import bar from 'bar';
foo.init();
10.8 複数行のインポートは、複数行の配列やオブジェクトリテラルと同様にインデントする必要があります。
ESLINT: オブジェクト - 中線 - 改行
なぜでしょうか。中括弧は、スタイルガイドの他のすべての中括弧ブロックと同じインデント規則に従い、末尾のコンマも同様です。
// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
// good
import {
longNameA,
longNameB,
longNameC,
longNameD,
longNameE,
} from 'path';
10.9 モジュールインポートステートメントでWebpackローダー構文を許可しません。
eslint: インポート/ウェブパックローダーなしの構文
なぜでしょうか。インポートでWebpack構文を使用するため、コードがモジュールバンドラーに結合されます。のローダー構文を使用することをお勧めします。
webpack.config.js
// bad
import fooSass from 'css!sass!foo.scss';
import barCss from 'style!css!bar.css';
// good
import fooSass from 'foo.scss';
import barCss from 'bar.css';
10.10 ファイル名拡張子を含めない
ESLINT: インポート/拡張機能
なぜでしょうか。拡張機能を含めると、リファクタリングが禁止され、すべてのコンシューマーにインポートするモジュールの実装の詳細が不適切にハードコードされます。
// bad
import foo from './foo.js';
import bar from './bar.jsx';
import baz from './baz/index.jsx';
// good
import foo from './foo';
import bar from './bar';
import baz from './baz';
11.1 イテレータを使わない。やのようなループの代わりにJavaScriptの高階関数を好む。eslint: イテレータ
なし制限なし構文
for-in
for-of
なぜでしょうか。これにより、不変のルールが適用されます。値を返す純粋な関数を扱うことは、副作用よりも推論が簡単です。
使う///////。。。配列を反復処理し、/ / 配列を生成してオブジェクトを反復処理できるようにします。
map()every()filter()find()findIndex()reduce()some()Object.keys()Object.values()Object.entries()
const numbers = [1, 2, 3, 4, 5];
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// good
let sum = 0;
numbers.forEach((num) => {
sum += num;
});
sum === 15;
// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
// bad
const increasedByOne = [];
for (let i = 0; i < numbers.length; i++) {
increasedByOne.push(numbers[i] + 1);
}
// good
const increasedByOne = [];
numbers.forEach((num) => {
increasedByOne.push(num + 1);
});
// best (keeping it functional)
const increasedByOne = numbers.map((num) => num + 1);
11.2 今のところジェネレータは使用しないでください。
なぜでしょうか。それらはES5にうまくトランスパイルしません。
11.3 ジェネレータを使用する必要がある場合、または当社のアドバイスを無視する場合は、ジェネレータの機能シグネチャの間隔が適切に配置されていることを確認してください。ESLINT: ジェネレーター-星の間隔
なぜでしょうか。 であり、 は同じ概念キーワードの一部である - は の修飾子ではない は、 とは異なる一意の構成体である。
function**functionfunction*function
// bad
function * foo() {
// ...
}
// bad
const bar = function * () {
// ...
};
// bad
const baz = function *() {
// ...
};
// bad
const quux = function*() {
// ...
};
// bad
function*foo() {
// ...
}
// bad
function *foo() {
// ...
}
// very bad
function
*
foo() {
// ...
}
// very bad
const wat = function
*
() {
// ...
};
// good
function* foo() {
// ...
}
// good
const foo = function* () {
// ...
};
12.1 プロパティにアクセスするときにドット表記を使用します。エスリント: ドット表記
const luke = {
jedi: true,
age: 28,
};
// bad
const isJedi = luke['jedi'];
// good
const isJedi = luke.jedi;
12.2 変数を持つプロパティにアクセスするときに括弧表記を使用します。
[]
const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');
12.3 べき乗を計算するときに指数演算子を使用します。エスリント:制限のないプロパティ
。
**
// bad
const binary = Math.pow(2, 10);
// good
const binary = 2 ** 10;
13.1 変数を宣言するには、常に or を使用します。そうしないと、グローバル変数になります。グローバル名前空間を汚染しないようにする必要があります。キャプテンプラネットは私たちにそれを警告しました。ESLINT: no-undef
prefer-const
const
let
// bad
superPower = new SuperPower();
// good
const superPower = new SuperPower();
13.2 変数または代入ごとに 1 つの OR 宣言を使用します。エスリント: 1-変数
const
let
なぜでしょうか。この方法で新しい変数宣言を追加する方が簡単で、a を a に交換したり、句読点のみの差分を導入したりすることを心配する必要はありません。また、すべての宣言を一度にジャンプするのではなく、デバッガーを使用して各宣言をステップ実行することもできます。
;,
// bad
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// bad
// (compare to above, and try to spot the mistake)
const items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
13.3 すべての をグループ化してから、すべての をグループ化します。
const
let
なぜでしょうか。これは、後で以前に割り当てられた変数の1つに応じて変数を割り当てる必要がある場合に便利です。
// bad
let i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;
// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;
13.4 必要な場所に変数を割り当てますが、適切な場所に配置します。
なぜでしょうか。 ブロックスコープであり、関数スコープではありません。
letconst
// bad - unnecessary function call
function checkName(hasName) {
const name = getName();
if (hasName === 'test') {
return false;
}
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
// good
function checkName(hasName) {
if (hasName === 'test') {
return false;
}
const name = getName();
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
13.5 変数の割り当てを連鎖させない。ESLINT: 複数割り当てなし
なぜでしょうか。変数の割り当てを連鎖させると、暗黙的なグローバル変数が作成されます。
// bad
(function example() {
// JavaScript interprets this as
// let a = ( b = ( c = 1 ) );
// The let keyword only applies to variable a; variables b and c become
// global variables.
let a = b = c = 1;
}());
console.log(a); // throws ReferenceError
console.log(b); // 1
console.log(c); // 1
// good
(function example() {
let a = 1;
let b = a;
let c = a;
}());
console.log(a); // throws ReferenceError
console.log(b); // throws ReferenceError
console.log(c); // throws ReferenceError
// the same applies for `const`
13.6 単項の増分と減分 (, ) の使用は避けてください。エスリントプラスプラスなし
++
--
なぜでしょうか。eslint のドキュメントによると、単項インクリメントおよびデクリメントステートメントはセミコロンの自動挿入の対象となり、アプリケーション内で値をインクリメントまたはデクリメントするとサイレントエラーが発生する可能性があります。また、 の代わりに or のようなステートメントで値を変化させる方が表現力豊かです。単項インクリメントおよびデクリメントステートメントを許可しないと、意図せずに値を事前インクリメント/プリデクリメントすることも防止され、プログラム内で予期しない動作が発生する可能性があります。
num += 1num++num ++
// bad
const array = [1, 2, 3];
let num = 1;
num++;
--num;
let sum = 0;
let truthyCount = 0;
for (let i = 0; i < array.length; i++) {
let value = array[i];
sum += value;
if (value) {
truthyCount++;
}
}
// good
const array = [1, 2, 3];
let num = 1;
num += 1;
num -= 1;
const sum = array.reduce((a, b) => a + b, 0);
const truthyCount = array.filter(Boolean).length;
13.7 課題の前後に改行を入れないようにする。割り当てが max-len
に違反している場合は、値を paren で囲みます。エスリント演算子-改行
。
=
なぜでしょうか。周囲を改行すると、割り当ての値が難読化される可能性があります。
=
// bad
const foo =
superLongLongLongLongLongLongLongLongFunctionName();
// bad
const foo
= 'superLongLongLongLongLongLongLongLongString';
// good
const foo = (
superLongLongLongLongLongLongLongLongFunctionName()
);
// good
const foo = 'superLongLongLongLongLongLongLongLongString';
13.8 未使用の変数を許可しません。ESLINT: 未使用の変数なし
なぜでしょうか。宣言され、コード内のどこにも使用されていない変数は、リファクタリングが不完全なためにエラーである可能性が高くなります。このような変数はコード内のスペースを占有し、読者による混乱を招く可能性があります。
// bad
const some_unused_var = 42;
// Write-only variables are not considered as used.
let y = 10;
y = 5;
// A read for a modification of itself is not considered as used.
let z = 0;
z = z + 1;
// Unused function arguments.
function getX(x, y) {
return x;
}
// good
function getXPlusY(x, y) {
return x + y;
}
const x = 1;
const y = a + 2;
alert(getXPlusY(x, y));
// 'type' is ignored even if unused because it has a rest property sibling.
// This is a form of extracting an object that omits the specified keys.
const { type, ...coords } = data;
// 'coords' is now the 'data' object without its 'type' property.
14.1宣言は最も近い囲み関数スコープの一番上に吊り上げられますが、その割り当てはそうではありません。 宣言は、時間的デッドゾーン(TDZ)と呼ばれる新しい概念に恵まれています。typeofがもはや安全でなくなった理由を知ることは重要です。
var
const
let
// we know this wouldn’t work (assuming there
// is no notDefined global variable)
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// the interpreter is hoisting the variable
// declaration to the top of the scope,
// which means our example could be rewritten as:
function example() {
let declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
// using const and let
function example() {
console.log(declaredButNotAssigned); // => throws a ReferenceError
console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
const declaredButNotAssigned = true;
}
14.2 匿名関数式は変数名をホイアップしますが、関数代入は上げません。
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}
14.3 名前付き関数式は、関数名や関数本体ではなく、変数名をホイアップします。
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
superPower(); // => ReferenceError superPower is not defined
var named = function superPower() {
console.log('Flying');
};
}
// the same is true when the function name
// is the same as the variable name.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
};
}
14.4 関数宣言は、その名前と関数本体を持ち上げます。
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
詳細については、Ben CherryによるJavaScript Scopeping & Hoistingを参照してください。
15.2 ステートメントのような条件ステートメントは、抽象メソッドで強制を使用して式を評価し、常に次の単純なルールに従います。
if
ToBoolean
''
if ([0] && []) {
// true
// an array (even an empty one) is an object, objects will evaluate to true
}
15.3 ブール値にはショートカットを使用し、文字列と数値には明示的な比較を使用します。
// bad
if (isValid === true) {
// ...
}
// good
if (isValid) {
// ...
}
// bad
if (name) {
// ...
}
// good
if (name !== '') {
// ...
}
// bad
if (collection.length) {
// ...
}
// good
if (collection.length > 0) {
// ...
}
15.5 中括弧を使用して、字句宣言を含むブロックと句を作成します(例:、、および)。エスリント: 大文字と小文字なしの宣言
case
default
let
const
function
class
なぜでしょうか。字句宣言はブロック全体に表示されますが、割り当てられた場合にのみ初期化され、到達したときにのみ発生します。これにより、複数の句が同じことを定義しようとすると問題が発生します。
switchcasecase
// bad
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {
// ...
}
break;
default:
class C {}
}
// good
switch (foo) {
case 1: {
let x = 1;
break;
}
case 2: {
const y = 2;
break;
}
case 3: {
function f() {
// ...
}
break;
}
case 4:
bar();
break;
default: {
class C {}
}
}
15.6 三項はネストしてはならず、通常は単一行の式であるべきです。エスリント:ネストされていない三元
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// split into 2 separated ternary expressions
const maybeNull = value1 > value2 ? 'baz' : null;
// better
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
15.7 不要な三項ステートメントは避けてください。ESLINT: 不要な三元なし
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
const quux = a != null ? a : b;
// good
const foo = a || b;
const bar = !!c;
const baz = !c;
const quux = a ?? b;
15.8演算子を混在させる場合は、括弧で囲みます。唯一の例外は、標準の算術演算子です:、、およびそれらの優先順位は広く理解されているためです。括弧内と括弧で囲むことをお勧めします。括弧が混在すると優先順位があいまいになる可能性があるためです。
ESLINT: 混合演算子なし
+
-
**
/
*
なぜでしょうか。これにより、読みやすさが向上し、開発者の意図が明確になります。
// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0;
// bad
const bar = a ** b - 5 % d;
// bad
// one may be confused into thinking (a || b) && c
if (a || b && c) {
return d;
}
// bad
const bar = a + b / c * d;
// good
const foo = (a && b < 0) || c > 0 || (d + 1 === 0);
// good
const bar = a ** b - (5 % d);
// good
if (a || (b && c)) {
return d;
}
// good
const bar = a + (b / c) * d;
16.1すべての複数行ブロックで中括弧を使用します。eslint: 非ブロックステートメント - 本体位置
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function foo() { return false; }
// good
function bar() {
return false;
}
16.2 複数行のブロックを と で使用している場合は、ブロックの右中括弧と同じ行に配置します。エスリント:ブレーススタイル
if
else
else
if
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
16.3 ブロックが常にステートメントを実行する場合、後続のブロックは不要です。を含むブロックに続くブロック内のAは、複数のブロックに分割できます。エスリント:他には戻りません
if
return
else
return
else if
if
return
if
// bad
function foo() {
if (x) {
return x;
} else {
return y;
}
}
// bad
function cats() {
if (x) {
return x;
} else if (y) {
return y;
}
}
// bad
function dogs() {
if (x) {
return x;
} else {
if (y) {
return y;
}
}
}
// good
function foo() {
if (x) {
return x;
}
return y;
}
// good
function cats() {
if (x) {
return x;
}
if (y) {
return y;
}
}
// good
function dogs(x) {
if (x) {
if (z) {
return y;
}
} else {
return z;
}
}
17.1 制御ステートメント ( など) が長くなりすぎたり、最大行長を超えたりした場合、各 (グループ化された) 条件を新しい行に入れることができます。論理演算子は行を開始する必要があります。
if
while
なぜでしょうか。行の先頭に演算子を要求すると、演算子の配置が維持され、メソッド チェーンと同様のパターンに従います。これにより、複雑なロジックを視覚的に追跡しやすくなり、読みやすさも向上します。
// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
thing1();
}
// bad
if (foo === 123 &&
bar === 'abc') {
thing1();
}
// bad
if (foo === 123
&& bar === 'abc') {
thing1();
}
// bad
if (
foo === 123 &&
bar === 'abc'
) {
thing1();
}
// good
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
// good
if (
(foo === 123 || bar === 'abc')
&& doesItLookGoodWhenItBecomesThatLong()
&& isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
17.2 制御ステートメントの代わりに選択演算子を使用しないでください。
// bad
!isRunning && startRunning();
// good
if (!isRunning) {
startRunning();
}
18.1 複数行コメントに使用します。
/** ... */
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
18.2 単一行のコメントに使用します。コメントの件名の上の改行に 1 行のコメントを配置します。ブロックの最初の行でない限り、コメントの前に空の行を入れます。
//
// bad
const active = true; // is current tab
// good
// is current tab
const active = true;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// also good
function getType() {
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
18.3 すべてのコメントは、読みやすくするためにスペースで始めます。エスリント:間隔を空けたコメント
// bad
//is current tab
const active = true;
// good
// is current tab
const active = true;
// bad
/**
*make() returns a new element
*based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
FIXME
TODO
FIXME: -- need to figure this out
TODO: -- need to implement
18.5 問題に注釈を付けるために使用します。
// FIXME:
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn’t use a global here
total = 0;
}
}
18.6 問題の解決策に注釈を付けるために使用します。
// TODO:
class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
19.1 2つのスペースに設定されたソフトタブ(スペース文字)を使用します。エスリント: インデント
// bad
function foo() {
∙∙∙∙let name;
}
// bad
function bar() {
∙let name;
}
// good
function baz() {
∙∙let name;
}
19.2先頭のブレースの前に1つのスペースを配置します。エスリント:ブロック前のスペース
// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog',
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog',
});
19.3 制御ステートメント(など)の左括弧の前にスペースを1つ入れます。関数呼び出しと宣言では、引数リストと関数名の間にスペースを入れないでください。エスリント: キーワード間隔
if
while
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
19.4 オペレーターをスペースで配置します。ESLINT: space-infix-ops
// bad
const x=y+5;
// good
const x = y + 5;
19.5 ファイルを 1 つの改行文字で終了します。エスリント:最終終了
// bad
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;
// bad
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;↵
↵
// good
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;↵
19.6 長いメソッドチェーン(2つ以上のメソッドチェーン)を作成する場合はインデントを使用します。先頭のドットを使用します。
行がメソッド呼び出しであり、新しいステートメントではないことを強調します。eslint: チェーン呼び出しごとの改行 プロパティ
の前に空白がない
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// bad
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
.attr('width', (radius + margin) * 2).append('svg:g')
.attr('transform', `translate(${radius + margin}, ${radius + margin})`)
.call(tron.led);
// good
const leds = stage.selectAll('.led')
.data(data)
.enter().append('svg:svg')
.classed('led', true)
.attr('width', (radius + margin) * 2)
.append('svg:g')
.attr('transform', `translate(${radius + margin}, ${radius + margin})`)
.call(tron.led);
// good
const leds = stage.selectAll('.led').data(data);
const svg = leds.enter().append('svg:svg');
svg.classed('led', true).attr('width', (radius + margin) * 2);
const g = svg.append('svg:g');
g.attr('transform', `translate(${radius + margin}, ${radius + margin})`).call(tron.led);
19.7 Leave a blank line after blocks and before the next statement.
// bad
if (foo) {
return bar;
}
return baz;
// good
if (foo) {
return bar;
}
return baz;
// bad
const obj = {
foo() {
},
bar() {
},
};
return obj;
// good
const obj = {
foo() {
},
bar() {
},
};
return obj;
// bad
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
// good
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
19.8 Do not pad your blocks with blank lines. eslint: padded-blocks
// bad
function bar() {
console.log(foo);
}
// bad
if (baz) {
console.log(quux);
} else {
console.log(foo);
}
// bad
class Foo {
constructor(bar) {
this.bar = bar;
}
}
// good
function bar() {
console.log(foo);
}
// good
if (baz) {
console.log(quux);
} else {
console.log(foo);
}
19.9 Do not use multiple blank lines to pad your code. eslint: no-multiple-empty-lines
// bad
class Person {
constructor(fullName, email, birthday) {
this.fullName = fullName;
this.email = email;
this.setAge(birthday);
}
setAge(birthday) {
const today = new Date();
const age = this.getAge(today, birthday);
this.age = age;
}
getAge(today, birthday) {
// ..
}
}
// good
class Person {
constructor(fullName, email, birthday) {
this.fullName = fullName;
this.email = email;
this.setAge(birthday);
}
setAge(birthday) {
const today = new Date();
const age = getAge(today, birthday);
this.age = age;
}
getAge(today, birthday) {
// ..
}
}
19.10 Do not add spaces inside parentheses. eslint: space-in-parens
// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}
19.11 Do not add spaces inside brackets. eslint: array-bracket-spacing
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);
19.12 Add spaces inside curly braces. eslint: object-curly-spacing
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
19.13 Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per above, long strings are exempt from this rule, and should not be broken up. eslint: max-len
Why? This ensures readability and maintainability.
// bad
const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;
// bad
$.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
// good
const foo = jsonData
&& jsonData.foo
&& jsonData.foo.bar
&& jsonData.foo.bar.baz
&& jsonData.foo.bar.baz.quux
&& jsonData.foo.bar.baz.quux.xyzzy;
// better
const foo = jsonData
?.foo
?.bar
?.baz
?.quux
?.xyzzy;
// good
$.ajax({
method: 'POST',
url: 'https://airbnb.com/',
data: { name: 'John' },
})
.done(() => console.log('Congratulations!'))
.fail(() => console.log('You have failed this city.'));
19.14 Require consistent spacing inside an open block token and the next token on the same line. This rule also enforces consistent spacing inside a close block token and previous token on the same line. eslint: block-spacing
// bad
function foo() {return true;}
if (foo) { bar = 0;}
// good
function foo() { return true; }
if (foo) { bar = 0; }
19.15 Avoid spaces before commas and require a space after commas. eslint: comma-spacing
// bad
const foo = 1,bar = 2;
const arr = [1 , 2];
// good
const foo = 1, bar = 2;
const arr = [1, 2];
19.16 Enforce spacing inside of computed property brackets. eslint: computed-property-spacing
// bad
obj[foo ]
obj[ 'foo']
const x = {[ b ]: a}
obj[foo[ bar ]]
// good
obj[foo]
obj['foo']
const x = { [b]: a }
obj[foo[bar]]
19.17 Avoid spaces between functions and their invocations. eslint: func-call-spacing
// bad
func ();
func
();
// good
func();
19.18 Enforce spacing between keys and values in object literal properties. eslint: key-spacing
// bad
const obj = { foo : 42 };
const obj2 = { foo:42 };
// good
const obj = { foo: 42 };
no-trailing-spaces
19.20 Avoid multiple empty lines, only allow one newline at the end of files, and avoid a newline at the beginning of files. eslint: no-multiple-empty-lines
// bad - multiple empty lines
const x = 1;
const y = 2;
// bad - 2+ newlines at end of file
const x = 1;
const y = 2;
// bad - 1+ newline(s) at beginning of file
const x = 1;
const y = 2;
// good
const x = 1;
const y = 2;
20.1 Leading commas: Nope. eslint: comma-style
// bad
const story = [
once
, upon
, aTime
];
// good
const story = [
once,
upon,
aTime,
];
// bad
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, birthYear: 1815
, superPower: 'computers'
};
// good
const hero = {
firstName: 'Ada',
lastName: 'Lovelace',
birthYear: 1815,
superPower: 'computers',
};
20.2 Additional trailing comma: Yup. eslint: comma-dangle
Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don’t have to worry about the trailing comma problem in legacy browsers.
// bad - git diff without trailing comma
const hero = {
firstName: 'Florence',
- lastName: 'Nightingale'
+ lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing']
};
// good - git diff with trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing'],
};
// bad
const hero = {
firstName: 'Dana',
lastName: 'Scully'
};
const heroes = [
'Batman',
'Superman'
];
// good
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
const heroes = [
'Batman',
'Superman',
];
// bad
function createHero(
firstName,
lastName,
inventorOf
) {
// does nothing
}
// good
function createHero(
firstName,
lastName,
inventorOf,
) {
// does nothing
}
// good (note that a comma must not appear after a "rest" element)
function createHero(
firstName,
lastName,
inventorOf,
...heroArgs
) {
// does nothing
}
// bad
createHero(
firstName,
lastName,
inventorOf
);
// good
createHero(
firstName,
lastName,
inventorOf,
);
// good (note that a comma must not appear after a "rest" element)
createHero(
firstName,
lastName,
inventorOf,
...heroArgs
);
Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called Automatic Semicolon Insertion to determine whether it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues.
// bad - raises exception
const luke = {}
const leia = {}
[luke, leia].forEach((jedi) => jedi.father = 'vader')
// bad - raises exception
const reaction = "No! That’s impossible!"
(async function meanwhileOnTheFalcon() {
// handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
// ...
}())
// bad - returns `undefined` instead of the value on the next line - always happens when `return` is on a line by itself because of ASI!
function foo() {
return
'search your feelings, you know it to be foo'
}
// good
const luke = {};
const leia = {};
[luke, leia].forEach((jedi) => {
jedi.father = 'vader';
});
// good
const reaction = 'No! That’s impossible!';
(async function meanwhileOnTheFalcon() {
// handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
// ...
}());
// good
function foo() {
return 'search your feelings, you know it to be foo';
}
22.2 Strings: eslint: no-new-wrappers
// => this.reviewScore = 9;
// bad
const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"
// bad
const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
// bad
const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string
// good
const totalScore = String(this.reviewScore);
22.3 Numbers: Use for type casting and always with a radix for parsing strings. eslint: radix
no-new-wrappers
Number
parseInt
Why? The function produces an integer value dictated by interpretation of the contents of the string argument according to the specified radix. Leading whitespace in string is ignored. If radix is or , it is assumed to be except when the number begins with the character pairs or , in which case a radix of 16 is assumed. This differs from ECMAScript 3, which merely discouraged (but allowed) octal interpretation. Many implementations have not adopted this behavior as of 2013. And, because older browsers must be supported, always specify a radix.
parseIntundefined0100x0X
const inputValue = '4';
// bad
const val = new Number(inputValue);
// bad
const val = +inputValue;
// bad
const val = inputValue >> 0;
// bad
const val = parseInt(inputValue);
// good
const val = Number(inputValue);
// good
const val = parseInt(inputValue, 10);
22.4 If for whatever reason you are doing something wild and is your bottleneck and need to use Bitshift for performance reasons, leave a comment explaining why and what you’re doing.
parseInt
// good
/**
* parseInt was the reason my code was slow.
* Bitshifting the String to coerce it to a
* Number made it a lot faster.
*/
const val = inputValue >> 0;
22.5 Note: Be careful when using bitshift operations. Numbers are represented as 64-bit values, but bitshift operations always return a 32-bit integer (source). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. Discussion. Largest signed 32-bit Int is 2,147,483,647:
2147483647 >> 0; // => 2147483647
2147483648 >> 0; // => -2147483648
2147483649 >> 0; // => -2147483647
22.6 Booleans: eslint: no-new-wrappers
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// best
const hasAge = !!age;
23.1 Avoid single letter names. Be descriptive with your naming. eslint: id-length
// bad
function q() {
// ...
}
// good
function query() {
// ...
}
23.2 Use camelCase when naming objects, functions, and instances. eslint: camelcase
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
23.3 Use PascalCase only when naming constructors or classes. eslint: new-cap
// bad
function user(options) {
this.name = options.name;
}
const bad = new user({
name: 'nope',
});
// good
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
});
23.4 Do not use trailing or leading underscores. eslint: no-underscore-dangle
Why? JavaScript does not have the concept of privacy in terms of properties or methods. Although a leading underscore is a common convention to mean “private”, in fact, these properties are fully public, and as such, are part of your public API contract. This convention might lead developers to wrongly think that a change won’t count as breaking, or that tests aren’t needed. tl;dr: if you want something to be “private”, it must not be observably present.
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';
// good
this.firstName = 'Panda';
// good, in environments where WeakMaps are available
// see https://kangax.github.io/compat-table/es6/#test-WeakMap
const firstNames = new WeakMap();
firstNames.set(this, 'Panda');
23.5 Don’t save references to . Use arrow functions or Function#bind.
this
// bad
function foo() {
const self = this;
return function () {
console.log(self);
};
}
// bad
function foo() {
const that = this;
return function () {
console.log(that);
};
}
// good
function foo() {
return () => {
console.log(this);
};
}
23.6 A base filename should exactly match the name of its default export.
// file 1 contents
class CheckBox {
// ...
}
export default CheckBox;
// file 2 contents
export default function fortyTwo() { return 42; }
// file 3 contents
export default function insideDirectory() {}
// in some other file
// bad
import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
// bad
import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
import forty_two from './forty_two'; // snake_case import/filename, camelCase export
import inside_directory from './inside_directory'; // snake_case import, camelCase export
import index from './inside_directory/index'; // requiring the index file explicitly
import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
// good
import CheckBox from './CheckBox'; // PascalCase export/import/filename
import fortyTwo from './fortyTwo'; // camelCase export/import/filename
import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
// ^ supports both insideDirectory.js and insideDirectory/index.js
23.7 Use camelCase when you export-default a function. Your filename should be identical to your function’s name.
function makeStyleGuide() {
// ...
}
export default makeStyleGuide;
23.8 Use PascalCase when you export a constructor / class / singleton / function library / bare object.
const AirbnbStyleGuide = {
es6: {
},
};
export default AirbnbStyleGuide;
23.9 Acronyms and initialisms should always be all uppercased, or all lowercased.
Why? Names are for readability, not to appease a computer algorithm.
// bad
import SmsContainer from './containers/SmsContainer';
// bad
const HttpRequests = [
// ...
];
// good
import SMSContainer from './containers/SMSContainer';
// good
const HTTPRequests = [
// ...
];
// also good
const httpRequests = [
// ...
];
// best
import TextMessageContainer from './containers/TextMessageContainer';
// best
const requests = [
// ...
];
23.10 You may optionally uppercase a constant only if it (1) is exported, (2) is a (it can not be reassigned), and (3) the programmer can trust it (and its nested properties) to never change.
const
Why? This is an additional tool to assist in situations where the programmer would be unsure if a variable might ever change. UPPERCASE_VARIABLES are letting the programmer know that they can trust the variable (and its properties) not to change.
const
EXPORTED_OBJECT.key
// bad
const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
// bad
export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
// bad
export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
// ---
// allowed but does not supply semantic value
export const apiKey = 'SOMEKEY';
// better in most cases
export const API_KEY = 'SOMEKEY';
// ---
// bad - unnecessarily uppercases key while adding no semantic value
export const MAPPING = {
KEY: 'value'
};
// good
export const MAPPING = {
key: 'value',
};
24.2 Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use and .
getVal()
setVal('hello')
// bad
class Dragon {
get age() {
// ...
}
set age(value) {
// ...
}
}
// good
class Dragon {
getAge() {
// ...
}
setAge(value) {
// ...
}
}
24.3 If the property/method is a , use or .
boolean
isVal()
hasVal()
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
24.4 It’s okay to create and functions, but be consistent.
get()
set()
class Jedi {
constructor(options = {}) {
const lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
set(key, val) {
this[key] = val;
}
get(key) {
return this[key];
}
}
25.1 When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass an object literal (also known as a "hash") instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of:
// bad
$(this).trigger('listingUpdated', listing.id);
// ...
$(this).on('listingUpdated', (e, listingID) => {
// do something with listingID
});
prefer:
// good
$(this).trigger('listingUpdated', { listingID: listing.id });
// ...
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingID
});
26.1 Prefix jQuery object variables with a .
$
// bad
const sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
const $sidebarBtn = $('.sidebar-btn');
26.2 Cache jQuery lookups.
// bad
function setSidebar() {
$('.sidebar').hide();
// ...
$('.sidebar').css({
'background-color': 'pink',
});
}
// good
function setSidebar() {
const $sidebar = $('.sidebar');
$sidebar.hide();
// ...
$sidebar.css({
'background-color': 'pink',
});
}
26.4 Use with scoped jQuery object queries.
find
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();
28.2 Do not use TC39 proposals that have not reached stage 3.
Why? They are not finalized, and they are subject to change or to be withdrawn entirely. We want to use JavaScript, and proposals are not JavaScript yet.
The Standard Library contains utilities that are functionally broken but remain for legacy reasons.
29.1 Use instead of global .
eslint: no-restricted-globals
Number.isNaN
isNaN
Why? The global coerces non-numbers to numbers, returning true for anything that coerces to NaN. If this behavior is desired, make it explicit.
isNaN
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
29.2 Use instead of global .
eslint: no-restricted-globals
Number.isFinite
isFinite
Why? The global coerces non-numbers to numbers, returning true for anything that coerces to a finite number. If this behavior is desired, make it explicit.
isFinite
// bad
isFinite('2e3'); // true
// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true
30.1 Yup.
function foo() {
return true;
}
mochaand
jestat Airbnb.
tapeis also used occasionally for small, separate modules.
map(),
reduce(), and
filter()optimized for traversing arrays?
Learning ES6+
Read This
Tools
Other Style Guides
Other Styles
Further Reading
Books
Blogs
Podcasts
This is a list of organizations that are using this style guide. Send us a pull request and we'll add you to the list.
This style guide is also available in other languages:
(MITライセンス)
著作権 (c) 2012 Airbnb
許可は、取得するすべての人に無料で付与されます。 このソフトウェアおよび関連するドキュメント ファイルのコピー ( 「ソフトウェア」)、以下を含む制限なしにソフトウェアを取り扱うこと。 使用、コピー、変更、マージ、公開する権利を制限なく、 本ソフトウェアのコピーを配布、サブライセンス、および/または販売し、 ソフトウェアが提供される人にそうすることを許可します。 次の条件:
上記の著作権表示およびこの許可表示は、 本ソフトウェアのすべてのコピーまたは重要な部分に含まれています。
本ソフトウェアは「現状有姿」で提供され、いかなる種類の保証もありません。 明示または黙示(以下の保証を含むがこれらに限定されない) 商品性、特定目的への適合性、および非侵害。 いかなる場合も、著者または著作権者は、いかなる責任も負わないものとします。 請求、損害、またはその他の責任(契約上の行為であるかどうかにかかわらず)、 不法行為またはその他の方法で、起因、起因、または関連して ソフトウェアまたはソフトウェアの使用またはその他の取引。
このガイドをフォークし、チームのスタイルガイドに合わせてルールを変更することをお勧めします。以下に、スタイルガイドの修正点をいくつか挙げることができます。これにより、マージの競合に対処することなく、スタイルガイドを定期的に更新できます。