◆ 配列っぽいのの配列化はsliceだけ
◆ 配列のシャローコピーならconcatでも

前にも思ったような気がするようなしないようなですが

配列をコピーする方法

a = [1,2,3] b = a

だと bの要素を書き換えるとaも変わります
反対にaを変えても bも変わります

b[1] = 0 a // [1, 0, 3] a.push(4) b // [1, 0, 3, 4]

なので concat や slice を使ってコピーします

a = [1, 2, 3] b = a.concat() c = a.slice() a[1] = 0 b // [1, 2, 3] c // [1, 2, 3]

aを変えてもbやcは変化なしです
配列の1階層目だけをディープコピーですが2階層目以降はシャローコピーなので今回みたいなプリミティブ値のときはいいですが 中にオブジェクト(配列も)が来たときにオブジェクトの中の変更は他のにも反映されます

配列っぽいオブジェクトの配列化

NodeListやHTMLCollectionやargumentsなどの配列っぽいオブジェクトはArray.prototypeを継承していなくて配列メソッドが使えません

使う方法は3つあります(もっとあるかも)

(1) __proto__を書き換えて継承させる
a = document.getElementsByTagName("a") a.__proto__ = Array.prototype a.map(function(e){return e.href})
この方法だと 元々のメソッド(この例だとgetElementsByTagNameで持ってくるHTMLCollectionのメソッド)が使えなくなるので使わないほうが良い時もあります

(2) callでむりやり
a = document.getElementsByTagName("a"); [].map.call(a, function(e){return e.href})
(ここだけセミコロンあるのは"["や"("から次の行が始まるとJavaScriptはつなげて1つの文にしようとするからです)

(3) 一端配列に変換
a = document.getElementsByTagName("a") arr = [] for(var i=0;i<a.length;i++){     arr[i] = a[i] } arr.map(function(e){return e.href})


ここからが今回の言いたかったこと!
(3)は(1)や(2)の方法で配列メソッドで行えます
私はよくsliceでやってます

slice(a,b)は 配列のa番目からb番目の要素を取り出して配列として返すメソッドです
引数がなければそのままの配列が返って来ます
配列っぽいのに使うと配列として返って来ます

a = document.getElementsByTagName("a") arr = [].slice.call(a) arr instanceof Array //true

配列のコピーのときにsliceじゃなくて気分でconcatにしたりもするので なんとなくconcatで配列へ変換しようとすると
[HTMLCollection[73]]
となりました

変換されてないです
concatだと無理なようです
配列コピーと混ざって使ってしまわないように配列コピーもsliceに統一するといいかもです

おまけ


色々なメソッドで配列に変換してみる

function arg2arr(){ var t = [] // for forEach method return { concat : [].concat.call(arguments), filter : [].filter.call(arguments, function(){return true}), forEach : ([].forEach.call(arguments, function(e){t.push(e)}), t), join : [].join.call(arguments, "絶対に来ない文字列!!!").split("絶対に来ない文字列!!!"), map : [].map.call(arguments, function(e){return e}), reduce : [].reduce.call(arguments, function(a,b,c){return c===1?[a,b]:(a.push(b),a)}), slice : [].slice.call(arguments), } } arg2arr(1,2,3)

concat: Array[1]     0: Arguments[3]     length: 1     __proto__: Array[0] filter: Array[3]     0: 1     1: 2     2: 3     length: 3     __proto__: Array[0] forEach: Array[3]     0: 1     1: 2     2: 3     length: 3     __proto__: Array[0] join: Array[3]     0: "1"     1: "2"     2: "3"     length: 3     __proto__: Array[0] map: Array[3]     0: 1     1: 2     2: 3     length: 3     __proto__: Array[0] reduce: Array[3]     0: 1     1: 2     2: 3     length: 3     __proto__: Array[0] slice: Array[3]     0: 1     1: 2     2: 3     length: 3     __proto__: Array[0] __proto__: Object

○concatは上に書いたとおり配列以外の要素だと その要素を配列の0番目の要素にして何かを追加する動作になります
なので変換はできてません

○filterは全部return trueにすることで元通りの配列になります

○forEachは何も返せないので一時変数tを用意してそこにforEach内でpushを使って追加して 最後にtを返すようにしてます
forEach+pushです

○joinはjoin+splitしてます
絶対に来ない文字列を探さないとダメです
また splitしてるので文字列になります
本来の形に戻せないものもあります

○mapはそのまま値を返します

○reduceはどんどんpushしていきます
最初だけ配列作る必要があります
初期値を渡せたらいいんですけどね

○sliceは一番簡単に出来る方法です