💡

あなたが知らないであろう15個の強力なJavaScriptのテクニック🗡🔈🔥

2023/03/02に公開
2

はじめに

この記事はこちらの記事の和訳となります。
なお、著者には許可をいただいております。是非原文もご覧ください。
拙訳なので、ご指摘などあればお待ちしております。

https://dev.to/ironcladdev/15-killer-js-techniques-youve-probably-never-heard-of-1lgp


Javascriptのバグ修正や答えを求めてGoogleやStackOverflowを探し回るのは楽しくないでしょう🏴‍☠️。

この記事では、生産性⚡を最大化し、苦痛🩸を最小化する、20個(訳註:正確には15個)の短く、パワフルなJavaScriptのテクニックを紹介します。

それではコードを見ていきましょう🤘

配列の重複を除去

配列から重複した要素を除去します。

const arr = ["a", "b", "c", "d", "d", "c", "e"]
const uniqueArray = Array.from(new Set(arr));

console.log(uniqueArray); // ['a', 'b', 'c', 'd', 'e']
説明

オブジェクト配列の重複を削除

それぞれが違う値とみなされるので、Setオブジェクトはオブジェクトの重複を削除できません。JSON.stringifyがここでは役に立ちます。

const arr = [{ key: 'value' }, { key2: 'value2' }, { key: 'value' }, { key3: 'value3' }];
const uniqueObjects = Array.from(
  new Set(
    arr.map(JSON.stringify)
  )
).map(JSON.parse)

console.log(uniqueObjects);

少し長いですが、より効率的な方法はこちらのコメントを参照してください。

説明
訳註参考

index付きの配列のイテレート

.map.forEachのイテレーション関数では、要素のindexを取得できます。

const arr = ['a', 'b', 'c'];
const letterPositions = arr.map(
  (char, index) => `${char} is at index ${index}`
)
説明

文字数で文字列を分ける

正規表現の関数.matchを使えば、n文字で文字を分けることができます。

const str = "asdfghjklmnopq";
const splitPairs = str.match(/.{1,2}/g);

console.log(splitPairs); // ['as', 'df', 'gh', 'jk', 'lm', 'no', 'pq']
説明

ここで使った正規表現/.{1,2}/gの中で、2という数字が何文字で分けたいかを表しています。あまりがある場合でもこのテクニックは有効です。あるいは、文字数nが動的に変更されることがある場合、new RegExpを使うことができます。

const splitPairsBy = (n) => str.match(new RegExp(`.{1,${n}}`, "g"))

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/match
https://stackoverflow.com/questions/6259515/how-can-i-split-a-string-into-segments-of-n-characters

文字を異なる文字ごとに分ける

もう一つの正規表現のテクニックとして、matchを使えば、例えば、"aabbc"を配列["aa", "bb", "c"]に分けることが可能です。

const str = "abbcccdeefghhiijklll";
const splitChars = str.match(/(.)\1*/g);

console.log(splitChars); // ['a', 'bb', 'ccc', 'd', 'ee', 'f', 'g', 'hh', 'ii', 'j', 'k', 'lll']
説明

オブジェクトをイテレートする

Object.entriesはJSONオブジェクトをkey-valueペアの配列に変換し、ループや配列のイテレータで反復処理を可能にしてくれます。

const obj = {
  "key1": "value1",
  "key2": "value2",
  "key3": "value3"
};
const iteratedObject = Object.entries(obj)
  .map(([key, value]) => `${key} = ${value}`);

console.log(iteratedObject); // ['key1 = value1', 'key2 = value2', 'key3 = value3']
説明

objObject.entriesに渡された場合、以下のようになります:

[
  ["key1", "value1"],
  ["key2", "value2"],
  ["key3", "value3"]
]

オブジェクトの分割代入と.map関数を使用すれば、key-valueにアクセスすることができます。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

Key-Valueの配列からオブジェクトへの変換

Object.fromEntriesを使えば、オブジェクトのKey-valueペアの配列から、key-valueのオブジェクトへ変換することができます。

const entryified = [
  ["key1", "value1"],
  ["key2", "value2"],
  ["key3", "value3"]
];

const originalObject = Object.fromEntries(entryified);

console.log(originalObject); // { key1: 'value1', ... }
説明

出現頻度をカウントする

配列の中で同じ要素が何個あるのかカウントしたい時があるかもしれません。.filter関数を使えば、それを達成することができます。

const occurrences = ["a", "b", "c", "c", "d", "a", "a", "e", "f", "e", "f", "g", "f", "f", "f"];
// 同じ文字を一度以上カウントしないようにユニークな配列を作成
const unique = Array.from(new Set(occurrences));

const occurrenceCount = Object.fromEntries(
  unique.map(char => {
    const occurrenceCount = occurrences.filter(c => c === char).length;
    return [char, occurrenceCount]
  })
)

console.log(occurrenceCount); // { a: 3, b: 1, c: 2, ... }

ワンライナーの堅牢なコードはこちらのコメントを見てみてください!

説明

replaceコールバック

.replace関数はただ固定の文字列を置き換えるだけにとどまりません。コールバックを渡して、その中でマッチした文字を使うことができます。

const string = "a dog went to dig and dug a doggone large hole";
const replacedString = string.replace(/d.g/g, str => str + "gy")

console.log(replacedString); // a doggy went to diggy and duggy a doggygone large hole
説明

オプショナルチェーン

JSでundefinedのエラーに遭遇した読者も多いことでしょうが、オプショナルチェーンはそれが発生するのを防いでくれます。

オプショナルチェーン (optional chaining) 演算子 (?.) は、接続されたオブジェクトチェーンの深くに位置するプロパティの値を、チェーン内の各参照が正しいかどうかを明示的に確認せずに読み込むことを可能にします。

const obj = {
  "a": "aaaaaaa",
  "b": null
};

console.log(obj.b.d); // throws an error

console.log(obj.b?.d); // returns undefined
説明

数字を制約する

たまに、数字をある範囲内に制約させたいと思うかもしれません。そのために、三項演算子を毎回使うのは面倒です。関数を使用すれば、より簡潔になります。

const constrain = (num, min, max) => {
  if(num < min) return min;
  else if(num > max) return max;
  else return num;
}

constrain(5, 1, 3) // 3
constrain(2, 1, 5) // 2
constrain(0, -100, 100) // 0

より良い方法はMath.minMath.maxをこのように使う方法でしょう:

const constrain = (num, min, max) => Math.min(Math.max(num, min), max)

@jonrandy に感謝を🙏

説明

配列の前後からインデックスする

.at関数は、正数、負数を渡すことによって、配列の前後から何番目かの要素を抜き出すことができます。

const arr = [1, 2, 3, 4, 5];

arr.at(0) // 1
arr.at(1) // 2
arr.at(-1) // 5
arr.at(-2) // 4

アルファベット順に並び替える

文字の配列をアルファベット順に並び替えます。

const words = ["javascript", "typescript", "python", "ruby", "swift", "go", "clojure"];
const sorted = words.sort((a, b) => a.localeCompare(b));

console.log(sorted); // ['clojure', 'go', 'javascript', 'python', 'ruby', 'swift', 'typescript']

💡Tip: a.localeCompare(b)b.localeCompare(a)に変えれば、昇順と降順を切り替えられます。

説明

Truthy/Falsyで並び替える

値がtruthyのものを先に、falsyなものを後に持ってくることで、truthy/falsyで配列を並べ替えることができます。

const users = [
  { "name": "john", "subscribed": false },
  { "name": "jane", "subscribed": true },
  { "name": "jean", "subscribed": false },
  { "name": "george", "subscribed": true },
  { "name": "jelly", "subscribed": true },
  { "name": "john", "subscribed": false }
];

const subscribedUsersFirst = users.sort((a, b) => Number(b.subscribed) - Number(a.subscribed))

Number(false)はゼロ値と同等でNumber(true)は1と同等です。そのため、sort関数に渡すことができます。

説明

小数をn桁で丸める

.toFixedを使うと、小数をn桁で丸めることができます。.toFixedは数字を文字に置き換えるので、数字に戻す必要があることに注意してください。

console.log(Math.PI); // 3.141592653589793
console.log(Number(Math.PI.toFixed(2)))
説明

ここまで読んでいただいてありがとうございました!
フィードバックお待ちしております。

参考

https://dev.to/ironcladdev/15-killer-js-techniques-youve-probably-never-heard-of-1lgp

Discussion

susiyakisusiyaki

オブジェクト配列の重複を削除

こちらの章に関しては、JSON.stringifyをする前にオブジェクトの中を並び替えないと、以下の2つのようなケースで重複していると判定されないです
JSのdeep equalの検証方法の記事や注釈などの記載があるといいかもしれません

{keyA: "hoge", keyB: "fuga"}
{keyB: "fuga", keyA: "hoge"}
s_yasunagas_yasunaga

ありがとうございます!注釈追加させていただきました!