noteのタイトル画像

ビットコイン自動トレードへの道 (番外編) (javascriptのsliceって紛らわしい)

Node.jsでBotを作成しているが、javascriptの配列操作で大活躍の「slice」メソッドで最初の頃、引数の扱いに慣れずに色々とポカをやった経験がある。
(いまも時々迷うこと多数)
なので、今回はsliceのあれこれを紹介したいと思っている。

何気に便利なsliceなので、あちこちで登場する。
配列の一番最後を取得したり、範囲を指定して部分配列を取得したりと非常に便利なんだが、時々「これで良かったんだっけ症候群」にかられることが多い。

sliceの構文は以下だ。

array.slice(start, [end]) 

array:配列(必須)
start:抽出する部分の先頭位置(必須)
end :抽出する部分の終端位置(任意)

となっている。
startはまあ良いでしょう。勘違いのしようがない。
で、問題は「end」の方だ。終端位置っていうから、終端の添え字を当てるのだとばっかり思っていた。

例えば次のような配列があったとする。

//       0 1 2 3 4 配列の添字
var a = [1,2,3,4,5];

コメントで書いた部分は配列アクセスで使用する場合の添え字だ。
他のプログラミング言語でも同じだと思う。
(プログラミング初心者の頃はそもそもなぜ添え字がゼロから始まるのか悩み、恨んだものだ。配列境界超えのエラーで落ちること多数)

次のアクセスをした場合、どの部分配列が戻されると予想するだろうか。

a.slice(2, 4)

上記の説明では、
 start :2 なのでa配列の[3]の値から始めると予想する。
 end :4 なのでa配列の[5]の値まで取ると予想する。
つまり、得られる結果は [3,4,5] だとばっかり思っていた。
だが、正解は予想に反して

[ 3,4 ]

となった。start位置はよいが、end位置が???な状況である。
そこでいくつかのパターンを試してみた。

//       0 1 2 3 4 配列の添字
var a = [1,2,3,4,5];

console.log(a.slice(0));
// -> [ 1,2,3,4,5 ]

console.log(a.slice(2));
// -> [ 3,4,5 ]

console.log(a.slice(4));
// -> [ 5 ]

console.log(a.slice(5));
//    配列の添字を超えたので、空配列が戻される
// -> []

console.log(a.slice(2,undefined));
//     undefined は定義が無いのと同じ
// -> [ 3,4,5 ]

console.log(a.slice(undefined, 4));
// (注意)
//      0 1 2 3 ← 配列の添字「4」の一つ手前の添字「3」までが戻される
// -> [ 1,2,3,4 ]

console.log(a.slice(2, 4));
// (注意)
//      2 3 ← 開始は添字の「2」だが、終了は添字の「4」から一つ手前の「3」までとなる
// -> [ 3,4 ]

console.log(a.slice(-1));
//      最後のデータが戻される
// -> [ 5 ]

console.log(a.slice(-2));
//      最後から数えて2つのデータが戻される
// -> [ 4,5 ]

console.log(a.slice(undefined, -1));
// (注意)
//      最初から、最後の一つ手前のデータまで戻される
// -> [ 1,2,3,4 ]

上記のようにコメントで「注意」と記述した部分が要注意なところ。
slice(-1) と slice(undefined, -1) では挙動はまったく異なる。
終端位置とは「添え字の一つ前までのデータが戻る」ということらしい。

配列操作に欠かせない「slice」「map」「reduce」だが、うっかり記述すると「動くんだけど、値が変」ってことになりかねないので注意が必要だ。

皆さまもsliceを扱うときには上記の「end」には注意された方が良いです。
今回はこの辺で。

ソフトウェア・エンジニアを40年以上やってます。 「Botを作りたいけど敷居が高い」と思われている方にも「わかる」「できる」を感じてもらえるように頑張ります。 よろしくお願い致します。