JSの配列要素に添字指定ではなくatメソッドを使用するデメリット

JavaScriptのatメソッドとは

JavaScriptのat()メソッドは、配列や文字列の要素にインデックスを使ってアクセスするためのメソッドです。

at() は正のインデックスだけでなく、負のインデックスにも対応しており、特に最後から数える場合に便利です。

JavaScript
// 添字指定の場合
const data = [10, 20, 30]
const lastData = data[data.length - 1]
console.log(lastData) // 30
JavaScript
// at()メソッドの場合
const data = [10, 20, 30]
const lastData = data.at(-1)
console.log(lastData) // 30

at()メソッドを使用する際の3つのデメリット

一見すると便利なat()メソッドですが、使い方を理解していない方には、3つのデメリットがあるので、使用する際には注意が必要です。

1. 返す値がわかりづらい

添字指定に比べて、at()メソッドは使い慣れている人でなければ返す値がわかりづらくなっています。

例えば、以下のat()メソッドを使用したコードの結果は何になるでしょうか?

JavaScript
console.log([10, 20, 30].at(7))
console.log([10, 20, 30].at('7'))
console.log([10, 20, 30].at(NaN))
console.log([10, 20, 30].at(undefined))
console.log([10, 20, 30].at(null))
console.log([10, 20, 30].at(''))
console.log([10, 20, 30].at('foo'))
console.log([10, 20, 30].at(false))
console.log([10, 20, 30].at(true))

ちなみに、添字指定の場合は、すべてundefinedになります。

JavaScript
// 以下の結果は、すべてundefinedになります。
console.log([10, 20, 30][7])
console.log([10, 20, 30]['7'])
console.log([10, 20, 30][NaN])
console.log([10, 20, 30][undefined])
console.log([10, 20, 30][null])
console.log([10, 20, 30][''])
console.log([10, 20, 30]['foo'])
console.log([10, 20, 30][false])
console.log([10, 20, 30][true])

[0], [1], [2] 以外はundefinedになるという単純明快な結果ですね。

そして、at()メソッドの場合は以下の結果になります。

JavaScript
console.log([10, 20, 30].at(7)) // undefined
console.log([10, 20, 30].at('7')) // undefined
console.log([10, 20, 30].at(NaN)) // 10
console.log([10, 20, 30].at(undefined)) // 10
console.log([10, 20, 30].at(null)) // 10
console.log([10, 20, 30].at('')) // 10
console.log([10, 20, 30].at('foo')) // 10
console.log([10, 20, 30].at(false)) // 10
console.log([10, 20, 30].at(true)) // 20

at()メソッドの場合は数値か数字の場合は、存在しなければundefinedを返します。

これは添字指定と同じですね。

しかし、NaN, undefined, null, '', 'foo', falseのように数値と数字以外(trueを除く)の指定だと、デフォルトのat(0)になる仕様になっています。

デフォルトがat(0)なので、at()のように空の場合もat(0)と同じ結果になります。

JavaScript
console.log([10, 20, 30].at()) // 10

さらにbooleanのtrueの場合は、at(1)と解釈されます。

JavaScript
console.log([10, 20, 30].at(true)) // 20

一見すると難しく見えますが、以下の法則になるので、これを覚えれば簡単です。

数値 or 数字 (0以上)・添字の値があれば結果を返す
・添字の値がなければundefined
・小数点を含む場合はMath.floor(値)になる
数値 or 数字 (負数)・at(-1)は最後の添字の結果を返す
・at(-7)のように添字の値がなければundefined
trueat(1) と同じ結果になる
それ以外at(0) と同じ結果になる

もし、この仕様を知らずに添字指定感覚で使用すると、想定外のバグを発生させてしまう可能性があります。

2. 小数点を含む数も使える

1.0や1.99などは添字指定だとundefinedを返しますが、at(1.0)やat(1.99)はMath.floor()を適用した状態で返すので、at(1)と同じになります。

JavaScript
const data = [10, 20, 30]
const result = data.at(1.99)
console.log(result) // 20

※ at()に変数を渡し、1.5以上を2にしたい場合は、Math.round()を別途使用する必要があります。

3. at()メソッドはES2022の機能

at()メソッドはES2022の機能なので、開発環境が対応してなければエディタ上でエラーが表示されます。

Property 'at' does not exist on type 'number[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2022' or later.ts(2550)

エラーに書かれているとおり、libを「ES2022」に変えればエラーは出なくなりますが、新規ではなく既存の開発環境の場合、libを変更すると書かれているコードによっては不具合などが発生する可能性があります。

tsconfig.app.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    // 中略
}

まとめ

使い方を理解していない方が使用する際のデメリットを挙げましたが、at()メソッドの使い方を理解した上で、libがES2022以上の環境で使用するならデメリットになりません。

使い方を理解している場合はコードの可読性が良くなりますし、TypeScriptの型を「string | undefined」で推論して返してくれるなどのメリットがありますので、積極的に使用することをオススメします。