複数の値のどれかにマッチ
before
if (a === 1 || a === 2 || a === 3) {};
after
if ([1, 2, 3].includes(a)) {};
N個の連番の配列を作る
before
const serialNumbers = [];
for (let i = 0; i < 100; ++i) {
serialNumbers.push(i);
}
after
const serialNumbers = [...Array(100)].map((_, i) => i);
メソッドチェーンで繋げられるので応用がしやすいです。
奇数の総和であればこう繋げられます
[...Array(100)]
.map((_, i) => i)
.filter((i) => i % 2)
.reduce((a, b) => a + b);
引数名を指定せず渡す
before
fetchSomething()
.then(data => console.log(data))
.catch(error => console.error(error));
after
fetchSomething().then(console.log).catch(console.error);
配列の分割代入
before
const list = ["a", "b"];
const a = list[0];
const b = list[1];
after
const list = ["a", "b"];
const [a, b] = list;
オブジェクトの分割代入
before
const obj = {a: 1, b: 2, c: 3};
const a = obj.a;
const rest = {b: obj.b, c: obj.c};
after
const obj = {a: 1, b: 2, c: 3};
const {a, ...rest} = obj;
ifの省略
before
if (a) console.log("truthy");
after(短絡評価)
a && console.log("truthy");
場合によってはifより取り回しがしやすいです。使い分けましょう。
if notの省略
注: if notでは0や空文字も判定されます。
before
if (!a) console.log("falsy");
after(短絡評価)
a || console.log("falsy");
場合によってはifより取り回しがしやすいです。使い分けましょう。
nullまたはundefinedのチェック
before
if (a === null || a === undefined) console.log("nullish");
after1(非推奨:同値演算子を使わないのでlinterによっては怒られます)
if (a == null) console.log("nullish");
after2(null合体演算子)
a ?? console.log("nullish");
代入したい値が存在しなければエラーにする
before
const a = null;
let value;
if (a === null || a === undefined) {
throw new Error("a is not defined");
} else {
value = a;
}
after
const a = null;
const value = a ?? (() => { throw new Error("a is not defined") })();
文字列代入の省略
注: 省略したいだけなら、ショートコーディング以外では使わない方が無難です
before
const greeting = (name) => `Hello, ${name}!`;
console.log(greeting("Alice")); // Hello, Alice!
after(タグ付きテンプレートリテラル)
const greeting = (name) => `Hello, ${name}!`;
console.log(greeting`Alice`); // Hello, Alice!
ObjectのOptional要素の確認の省略
before
const obj = {};
if (obj.fnc) obj.fnc();
if (obj.options) obj.options.a;
after(オプショナルチェーン)
const obj = {};
obj.fnc?.();
obj.options?.a;
Objectのキーの省略
before
const a = "hi";
const b = 123;
const data = {
a: a,
b: b
}
after
const a = "hi";
const b = 123;
const data = {a, b}
Objectの一部を取り除く
before
const dict = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6};
const cLess = {a: dict.a, b: dict.b, d: dict.d, e: dict.e, f: dict.f};
after
const dict = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6};
const cLess = (({c, ...rest}) => rest)(dict);
delete dict.c;
も楽ですが、dictを破壊してしまいます。
Objectの一部を取り出す
before
const dict = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6};
const ace = {a: dict.a, c: dict.c, e: dict.e};
after
const dict = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6};
const ace = (({a, c, e}) => ({a, c, e}))(dict);
読みにくくなることが多いので、使い所は考えた方がいいでしょう。
Objectの一部をkeyを使って取り出す
before
const dict = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 };
const keys = ["a", "c", "e"];
const ace = keys.reduce((obj, key) => {
obj[key] = dict[key];
return obj;
}, {});
console.log(ace); // { a: 1, c: 3, e: 5 }
after
const dict = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 };
const keys = ["a", "c", "e"];
const ace = Object.fromEntries(
Object.entries(dict).filter(([key]) => keys.includes(key))
);
console.log(ace); // { a: 1, c: 3, e: 5 }
Optionalな引数に値を代入する
before
const greet = (name) => {
if (name === undefined) name = "Guest";
console.log("Hello, " + name + "!");
};
greet(); // 出力: Hello, Guest!
greet("John"); // 出力: Hello, John!
after(デフォルトパラメータ)
const greet = (name = "Guest") => console.log("Hello, " + name + "!");
greet(); // 出力: Hello, Guest!
greet("John"); // 出力: Hello, John!
条件によって違う値を入れる
before
let result;
if (condition) {
result = "a";
} else {
result = "b";
}
after
const result = condition ? "a" : "b";
三項演算子は代入やreturnで使うと見やすいです。ただし、ネストすると可読性が落ちるので注意が必要です。
if文で戻り値を使わない処理を実行してから値を返す
before
const getUserType = (isAdmin) => {
if (isAdmin) {
console.log("管理者です");
return "admin";
} else {
console.log("一般ユーザーです");
return "user";
}
};
const userType = getUserType(true); // 管理者です
console.log(userType); // admin
after
const getUserType = (isAdmin) =>
isAdmin
? (console.log("管理者です"), "admin")
: (console.log("一般ユーザーです"), "user");
const userType = getUserType(true); // 管理者です
console.log(userType); // admin
カンマ演算子は左から右へ式を評価し、最後の式の値を返します
複数の条件によって違う値を入れる
before
let x;
if (condition) {
x = "a";
} else if (condition2) {
x = "b";
} else {
x = "c";
}
after1(即時実行関数, 可読性 ⚪︎)
const x = (() => {
if (condition) return "a";
if (condition2) return "b";
return "c";
})();
after2(短絡演算, 可読性 △)
const x = (condition && "a") || (condition2 && "b") || "c";
after3(三項演算子のネスト, 可読性 x)
const x = condition ? "a" : condition2 ? "b" : "c";
慣れないと読みにくいですが、代入時に値が決定する安心感があります。
さらに条件が増えた時を考えたら、即時実行関数が無難です。
キーから値を得る(辞書)
before
const myMap = (key) => {
switch (key) {
case "a":
return "alpha";
case "b":
return "bravo";
case "c":
return "charlie";
default:
break;
}
};
console.log(myMap("a")); // alpha
after1(Object)
const myMap = {
a: "alpha",
b: "bravo",
c: "charlie",
};
console.log(myMap["a"]); // alpha
after2(Map)
const myMap = new Map([
["a", "alpha"],
["b", "bravo"],
["c", "charlie"],
]);
console.log(myMap.get("a")); // alpha
ObjectとMapの比較はこちら
条件によって配列に値を入れる
before
const a = [1, 2];
if (condition) a.push(3, 4)
after
const a = [1, 2, ...(condition ? [3, 4] : [])];
undefinedかもしれない配列同士を結合
before
const a = [1, 2];
const b = undefined;
const result = [];
if (a) result.push(a);
if (b) result.push(b);
after1
const a = [1, 2];
const b = undefined;
const result = [...(a ?? []), ...(b ?? [])];
after2
const a = [1, 2];
const b = undefined;
const result = [].concat(a, b).filter(Boolean); // or .filter(v => v)
条件によってオブジェクトにkey/valueを追加
before
let obj;
if (condition) obj = {a: 1, b: 2, c: 3}
else obj = {a: 1}
after1
const obj = {a: 1};
if (condition) Object.assign(obj, {b: 2, c:3});
after2
const obj = {
a: 1,
...(condition && {b: 2, c: 3}),
};
オブジェクトに要素が存在しない場合にkey/valueを追加
before
const obj = {a: "a"};
if (!obj.b) obj.b = "b";
after(null合体代入)
const obj = {a: "a"};
obj.b ??= "b";
配列の中身をユニークな値にする
before
const uniq = [1, 2, 1, 3, 1, 5].filter(
(value, index, array) => array.indexOf(value) === index
);
after
const uniq = [...new Set([1, 2, 1, 3, 1, 5])];
連続的にインスタンスの値を処理する
before
class Point {
sum = 0;
add(x) {
this.sum += x;
}
}
const myPoint = new Point();
myPoint.add(10);
myPoint.add(5);
console.log(myPoint.sum); // 15
after1(class版メソッドチェーン)
class MyPoint {
sum = 0;
add(x) {
this.sum += x;
return this;
}
}
const myPoint = new MyPoint();
myPoint.add(10).add(5);
console.log(myPoint.sum); // 15
after2(関数版メソッドチェーン)
const createPoint = () => ({
sum: 0,
add(x) {
this.sum += x;
return this;
},
});
const myPoint = createPoint();
myPoint.add(10).add(5);
console.log(myPoint.sum); // 15
thisを返せば、連続的な処理ができます。class版の方が無難です。
(関数の場合、引数を取って代入しておけばコンストラクタの代わりになり、シンボルを使えばprivateの代わりになります)
部分適用で再利用可能な関数を作る
before
const createGreeting = (greeting, name) => `${greeting}, ${name}!`;
const sayHello = (name) => createGreeting("Hello", name);
const sayHi = (name) => createGreeting("Hi", name);
console.log(createGreeting("Hello", "John")); // Hello, John!
console.log(createGreeting("Hi", "Alice")); // Hi, Alice!
after1(bind)
const createGreeting = (greeting, name) => `${greeting}, ${name}!`;
const sayHello = createGreeting.bind("Hello");
const sayHi = createGreeting.bind("Hi");
console.log(sayHello("Hello", "John")); // Hello, John!
console.log(sayHi("Hi", "Alice")); // Hi, Alice!
after2(カリー化)
const createGreeting = (greeting) => (name) => `${greeting}, ${name}!`;
const sayHello = createGreeting("Hello");
const sayHi = createGreeting("Hi");
console.log(sayHello("John")); // Hello, John!
console.log(sayHi("Alice")); // Hi, Alice!
console.log内の文字結合の省略
before
console.log("1 plus 1 is " + (1 + 1));
after1(テンプレートリテラル)
console.log(`1 plus 1 is ${1 + 1}`);
after2(カンマ)
console.log("1 plus 1 is", 1 + 1);
表形式のデータを見やすくログに出す
before
console.log([
[1, 2],
[3, 4],
]);
console.log({
a: {x: 1, y: 2},
b: {x: 3, y: 4},
});
after
console.table([
[1, 2],
[3, 4],
]);
console.table({
a: {x: 1, y: 2},
b: {x: 3, y: 4},
});
繰り返し処理の最適化
before
const fibonacci = (n) => {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
};
console.log(fibonacci(45)); // 1134903170
// 実行時間: 5000ms
after(メモ化)
const memo = [0, 1]; // ここに計算結果を追加していきます
const fibonacci = (n) => {
if (memo[n] !== undefined) return memo[n];
memo[n] = fibonacci(n - 1) + fibonacci(n - 2);
return memo[n];
};
console.log(fibonacci(45)); // 1134903170
// 実行時間: 1ms
計算結果を保存してそれを使いまわすようにすれば、計算を減らせます。
テンプレートリテラルに複雑な処理をする
before
const i18n = (key) => {
const translations = {
Hello: "こんにちは",
Goodbye: "さようなら",
};
return translations[key] || key;
};
console.log(i18n("Hello") + "😃 " + i18n("Goodbye") + "👋!"); // こんにちは😃 さようなら👋!
after(タグ付きテンプレートリテラル)
const i18n = (strings, ...values) => {
const translations = {
Hello: "こんにちは",
Goodbye: "さようなら",
};
return strings.reduce((result, string, i) => {
const translated = translations[values[i]] || values[i];
return result + string + (translated || "");
}, "");
};
console.log(i18n`${"Hello"}😃 ${"Goodbye"}👋!`); // こんにちは😃 さようなら👋!