🤖

覚えておきたい可読性を上げるJavaScriptの書き方

2022/08/06に公開

else ifを減らす

  • else ifが出現したら、最適化できないかどうか検討します。
  • 名前から食べ物の価格を計算する必要がある場合を例にします。
const getPrice = (name) => {
    if (name === '🍔') {
        return 20;
    } else if (name === '🍟') {
        return 15;
    } else if (name === '🍦') {
        return 5;
    }
}

console.log(getPrice('🍔')); // 20
  • この書き方では条件判定文が多くなり、次に食べ物を追加したい場合はelse if を追加する必要があり、オープン・クローズの原則にもある程度違反します。
  • Map構造のデータを使用して、すべての食べ物を保存するオブジェクトを作成します。
const foodMap = {
    '🍔': 20,
    '🍟': 15,
    '🍦': 10,
    '🍩': 10,
    '🍪': 4,
    '🍫': 8,
    '🍬': 1,
    '🍭': 2,
}
const getPrice = (name) => {
    return foodMap[name];
}

console.log(getPrice('🍟')); // 20
  • 食べ物を追加する際に getPriceのロジックを変更する必要が無くなりました。

冗長になるループの代わりにパイプライン操作

  • こんな食べ物リストがあります
const foods = [{
    name: '🍔',
    group: 1
}, {
    name: '🍟',
    group: 1
}, {
    name: '🍦',
    group: 2
}, {
    name: '🍩',
    group: 2
}];
  • groupが1に属する食べ物を見つけたい場合、まずforループを使った方法が考えられます。
  • もっとコードを簡潔にわかりやすくするために、forループの代わりにfiltermapを使用するように置き換えます。
  • 最初に配列をフィルタリングしてからmapで取得したい形に再編成します。
// ❌
const names = [];
for (let i=0;i<foods.length;i++){
    if (foods[i].group === 1){
        names.push(foods[i].name);
    }
}

// ✅
const names = foods.filter(food => food.group === 1)
    .map(food => food.name);
console.log(names); // ['🍔', '🍟']

find関数による冗長なループの置き換え

  • findは、配列から特定のプロパティ値で見つけたい場合に役立ちます。
// ❌
const findFood = (foods, name, group) => {
    for (let i=0;i<foods.length;i++) {
        if (foods[i].name === name && foods[i].group === group) {
            return foods[i];
        }
    }
}
const humbugger = findFood(foods, '🍔', 1);

// ✅
const humbugger =  foods.find(food => food.name === '🍔' && food.group === 1);
console.log(humbugger); // {name: '🍔', group: 1}

includes関数によるループの置き換え

  • 配列に特定の値が含まれているかどうかを調べたい場合、includesを使用するとコードが簡潔になります。
const foods = ['🍔', '🍟', '🍦', '🍩', '🍪', '🍫', '🍬', '🍭', '🍮', '🍯'];
// ❌
let hasCookie = false;
for (let i = 0; i < foods.length; i++) {
    if (foods[i] === '🍪') {
        hasCookie = true;
        break;
    }
}

// ✅
const hasCookie = foods.includes('🍪');
console.log(hasCookie); // true

早期return

  • selectKeyが存在しない場合は結果が確定しているため、以降のコードを読み続ける必要はありません。そうしないと必要以上にコードを読むコストが発生してしまいます。
// ❌
const activeParentKeys = (selectedKey) => {
    let result = [];
    if(selectedKey) {
        if (selectedKey !== 'key1') {
            result = getParentKeys(selectedKey);
        }
    }
    return result;
}

// ✅
const activeParentKeys = (selectedKey) => {
    if (!selectedKey) return [];
    if (selectedKey !== 'key1') {
        return getParentKeys(selectedKey)
    }
    return [];
}

オブジェクト渡し

  • 関数に渡すパラメータが少ない場合は気になりませんが数が増えると少々煩雑になります。
  • オブジェクト全体を直接渡すことにより、パラメーターのリストが短くなり、コードが読みやすくなります。
  • ただし、モジュール強度がスタンプ結合となるため、一概に良いとは言えません。私はこの書き方が好きです。
const data = {
    icon: '📖',
    content: 'Document'
}
// ❌
const getDocDetail = (icon, content) => {
    console.log(icon);
    console.log(content);
}
getDocDetail(data.icon, data.content);

// ✅
const getDocDetail = (data) => {
    const {icon, content} = data;
    console.log(icon);
    console.log(content);
}

演算子の使用

  • 新しい変数を作成する場合、参照する変数がnullまたは未定義であるかどうかを確認する必要がある場合、簡単な方法で記述できます。
// ❌
if (selectedKey !== null && selectedKey !== undefined) {
    const activeKey = selectedKey;
} else {
    const activeKey = '';
}

// ✅
const activeKey = selectedKey ?? '';

Discussion