どの方法もリスクがあり最適解がない。
標準API
const A = ['最初', '中間', '最後'] const methods = [ // (a)=>a.pop(), // 配列内容を変更してしまう破壊メソッド! (a)=>a[a.length-1], // (a)=>a.slice(-1)[0], // (a)=>a.at(-1), // ES2022 Chrome 92 ] for (let m of methods) { console.log(m(A), m) }
方法 | 残念点 |
---|---|
a.pop() |
配列内容を変更してしまう破壊メソッド |
a[a.length-1] |
冗長かつ判りにくい |
a.slice(-1)[0] |
冗長かつ判りにくい |
a.at(-1) |
ES2022(Chrome 92以降で使用可) |
a.at(-1)
が最も判りやすいが、古いブラウザで動作しないa.slice(-1)[0]
はほぼ全環境で実行可能a[a.length-1]
はa
の参照が二回あるため同変数名が繰り返され冗長a.pop()
は破壊メソッドのため参照には不適切
実行可能性を優先すると2のa.slice(-1)[0]
を使うことになる。いずれ1のa.at(-1)
か、もっと良いAPIに置き換わる日が来るはず。だが、それまではa.slice(-1)[0]
という可読性の低いAPIを使わざるを得ない。
できれば以下のように参照したかったが、標準APIにはない。OTZ
a.last a[-1]
自作API
ないなら作ればいい。
名前汚染してもいいなら、次のように定義できる。
array-last.js
Object.defineProperty(Array.prototype, 'last', { get: function() { return this[this.length-1] } });
Array
にlast
ゲッターを定義した。次のように呼び出す。
A.last
できた。最高!
あとはこれをarray-last.js
などの名前を付けてファイルに保存しHTMLで読み込めば使い回せる。次のように。
<script src="array-last.js"></script> <script> window.addEventListener('DOMContentLoaded', async(event) => { const A = ['最初', '中間', '最後'] console.log(A.last) // 最後 }) </script>
問題
- 将来の拡張により名前重複しバグる可能性あり(標準API、他ライブラリ)
- 毎回
<script src="array-last.js"></script>
で読み込むの面倒
グローバル汚染、prototype
汚染は、一般的に危険であり非推奨。もし標準APIに同名のそれが実装されたとき、微妙な挙動の違いなどでバグが起きかねない。他のライブラリで似たようなことをして名前が重複したとき、読み込んだ順によってどれが実行されるか決まってしまい、微妙な挙動の違いなどでバグが起きかねない。
ポリフィルはダメ絶対
ポリフィルでat()
を実装するのも手だ。誰かに最適なコードを作ってもらい、自分はそれをCDNでお手軽に利用する。最高である。
と思っていたらマルウェアが仕込まれて事件になっていた。OTZ
もう他人の書いたコードなんて信じない💢
結論
最後の要素を取得する最適解はない。
選べ。次の中から犠牲にすべきものを。
コード | 長所 | 短所 |
---|---|---|
a.slice(-1)[0] |
どの環境でも動作する | 可読性が低い |
a.at(-1) |
標準API。可読性が高い | ES2022(Chrome 92以降で使用可) |
a.last |
可読性が高い | prototype 汚染。<script> 読込必要 |
公式さん早くlast
API作って。[-1]
もね。(合わせてfirst
も頼む)