JavaScriptには、関数の引数情報を表すArugmentsオブジェクト、DOM APIのgetElementsByTagName()が返すNodeListオブジェクトのように、配列だけど配列でないオブジェクト(以下、配列風オブジェクトと呼ぶ)が存在する。
配列ではないので、単純に配列(Arrayオブジェクト)のメソッドをそのまま呼ぶ事はできない。call()やapply()を用いて呼べばOKなメソッドもあるが、場合によっては配列に変換しないとダメとか、むしろ変換しちゃったほうが何かと都合がいいとかあるだろう。
変換方法は以下のコードを1行実行するだけで良い。
- var array = Array.prototype.slice.apply(arguments);
var array = Array.prototype.slice.apply(arguments);
Arrayオブジェクトのslice(start, end)は、配列から指定したインデックスの要素を抜き出した新しい配列を返す(インデックスを指定しなかったら中身が全く同じの新しい配列を返す)メソッドで、このメソッドを使う事で配列風オブジェクトから配列が返ってくる。
そもそも、なんでこいつを使うと本物の配列が返るのかというと、配列風オブジェクトの特徴が
- lengthを持つ
- 数値プロパティを持つ(プロパティ名が数値なので、arguments[1]とやると値を取得できる)
であり、slice()が以下のような実装になっているからだと思う。
- var slice = function(start, end) {
- var newArr = [];
- var i = start || 0;
- end = end || this.length;
-
- for (; i < end; i++) {
- newArr.push(this[i]);
- }
-
- return newArr;
- }
var slice = function(start, end) {
var newArr = [];
var i = start || 0;
end = end || this.length;
for (; i < end; i++) {
newArr.push(this[i]);
}
return newArr;
}
↑だいぶざっくりと書いているので気をつけてください(startの値が負数だとか、endの値が配列の長さ以上だとか考慮してないっす)。メソッドになっていないのも勘弁してください。
ポイントはthis(apply(), call()で呼べばthisは配列風オブジェクト)とpush()のところで数値でプロパティ値を取得してるところかな。