arguments と Function.apply(this) を上手に扱う

追記: apply("add string") で何が渡ってるのか見てみました。
Chrome以外のブラウザは new String("add string") が渡されてました

function func1(var_args) {
  func2.apply("add string", arguments); // this に "add string" そのものを渡す
}
function func2(var_args) {
  alert("typeof this = " + typeof this);
  if (this instanceof String) {
    alert("this instanceof String");
  }

  alert(this); // -> "add string" 
}
typeof this this instanceof String
Google Chrome4 "string" false
Safari4 "object" true
Firefox2 〜 3.5 "object" true
IE8 "object" true
Opera9.2 〜 10 "object" true

あれ? (つд⊂)ゴシゴシ WebKitChrome なのかな?

素の string だと…

  var str = "string";

  alert("typeof str = " + typeof str);
  if (str instanceof String) {
    alert("str instanceof String");
  }
typeof str str instanceof String
Google Chrome4 "string" false
Safari4 "string" false
Firefox2 〜 3.5 "string" false
IE8 "string" false
Opera9.2 〜 10 "string" false

こうなりますが、new String("add string") だと

typeof this this instanceof String
Google Chrome4 "object" true
Safari4 "object" true
Firefox2 〜 3.5 "object" true
IE8 "object" true
Opera9.2 〜 10 "object" true

こうなりますね。Chrome 以外のブラウザでは、"add string" ではなく、new String("add string") なオブジェクトが渡っているようです。

os0x さんご指摘のように、toString() すると文字列が取れてくるけど、string から派生して string のように使えるオブジェクトが渡っていますね。jsライブラリの型判定関数(isString 等)や JSON.stringify に this を渡す場合は、素のオブジェクトに変換( this.toString() とか this + "" )してから渡すと安全ですね。

本文

JavaScript は arguments キーワードにより可変長引数が扱えます。
func.apply(this) や func.call(this) で func() 内での this を制御することもできます。

今日は「this はスコープを制御する以外にも使い道がある」ってことを書きます。

教科書に書かれてそうな arguments の使い方

以下は、func1() の引数の先頭に、文字列("add string")を追加し、関数func2を呼び出します。

function func1(var_args) {
  var arg = _ary(arguments); // 配列に変換
  arg.unshift("add string"); // 先頭に挿入
  func2.apply(this, arg); // 加工した配列を渡す
}
function func2(var_args) {
  var ary = _ary(arguments); // 配列に変換
  var str = ary.shift(); // 先頭要素を切り出し
  alert(str); // -> "add string"
}
// arguments を配列に変換する
function _ary(fake) {
  var rv = [], ri = -1, i = 0, iz = fake.length;

  for (; i < iz; ++i) {
    rv[++ri] = fake[i];
  }
  return rv;
}

func1();

さっき気が付いた使い方

this が自由に使えるケースでは、すっきり書けます。

function func1(var_args) {
  func2.apply("add string", arguments); // this に "add string" そのものを渡す
}
function func2(var_args) {
  alert(this); // -> "add string" 
}

func1();

this には、hash を渡したり, arguments の中身も渡せます。
# func2.call(arguments, "add string"); はうごきません(スコープの問題)

function func1(var_args) {
  func2.call(_ary(arguments), "add string"); // 配列化した引数を this に指定
}
function func2(arg) {
  alert(this[0].key); // 1
  alert(arg); // -> "add string"
}
function _ary(fake) {
  var rv = [], ri = -1, i = 0, iz = fake.length;

  for (; i < iz; ++i) {
    rv[++ri] = fake[i];
  }
  return rv;
}

func1({ key: 1 }); // { key: 1 } を渡す

まとめ

引数は this でも渡せます。this も使ってスッキリ書きましょう。
追記
関数内で this は上書できないので、普通の引数とはちょっと違います。

this = "hoge"; // NG

お約束

js の this とスコープをちゃんと理解していない方にはお勧めできません。