FirefoxにおけるArray#concatは strict mode function 相当
Array.prototype
の大半のメソッドは、配列以外のオブジェクト(NodeListなどの擬似配列など)にも転用できるように汎用的に定義されている。Array.prototype.concat
もその一つだけど、他のメソッドとは異なりthis
値に配列っぽさは求められておらず、どんなオブジェクトでもよい。this
値は引数と同じように処理される。
Array.prototype.concat.call(1, 2, 3, 4, 5); //=> [1, 2, 3, 4, 5] // ? Array.prototype.concat.call("A", "B", "C"); //=> ["A", "B", "C"] // ?
ただし、通常の関数 (non-strict mode function) ではthis
値は必ずオブジェクトになる。数値はNumberオブジェクトに、文字列はStringオブジェクトにラップされてしまう。?
と書いたのはそのこと。Firefox以外のブラウザでは次のような結果になる。
var array = Array.prototype.concat.call(1, 2, 3, 4, 5); typeof array[0]; //=> "object" typeof array[1]; //=> "number"
Firefoxではtypeof array[0];
の戻り値は"number"
になる。this
値はラップされない。strict mode function として定義されているのだろうか。
If
Annotated ES5this
is evaluated within strict mode code, then thethis
value is not coerced to an object.
function nonStrictFn() { return this; } function strictFn() { "use strict"; return this; } typeof nonStrictFn.call(9); //=> "object" typeof strictFn.call(9); //=> "number"
Generic method
FirefoxではString.prototype
やArray.prototype
のメソッドを転用しやすいように Generic method が用意されている。例えば、Array.prototype.concat.call
の代わりにArray.concat
と書ける。
Array.concat(1, 2, 3, 4, 5); //=> [1, 2, 3, 4, 5]
このとき、戻り値の一つ目の要素がオブジェクトにラップされていたら混乱を招くと思う。これがArray.prototype.concat
の実装に影響を与えているんだと思う。
以前書いたFirefox以外の実装にも Generic method を定義するためのスクリプトもFirefoxの実装に合わせることにした。もちろん、Array.prototype.concat
の方は弄らない。
転用の必要性
そもそも、Array.prototype.concat
は転用する必要がないように思える。[].concat(item1, item2, ...)
で事足りる。
var array; array = [].concat(1, 2, 3, 4, 5); //=> [1, 2, 3, 4, 5] typeof array[0]; //=> "number"
Array.prototype
自体も配列 (Array.isArray(Array.prototype) === true
) なので、Array.prototype.length
が弄られていないという前提の下、次のようにも書ける。
// Function#callを使わない Array.prototype.concat(1, 2, 3, 4, 5); //=> [1, 2, 3, 4, 5]