JavaScriptのapplyと再帰呼び出し
最近ちまちまと家でJavaScriptを書いています。
applyについてちょっと勉強してみました。元ネタはサイ本より。
JavaScriptでは可変引数が標準でサポートされているので、任意の引数からの和を算出する関数sum()を作る
function sum() { var total = 0; for (var i = 0; i < arguments.length; i++){ total += arguments[i]; } return total; }
そこで、
alert(sum(1, 2, 3, 4)); // 結果は10
と上手く行くが、引数が配列だと
alert(sum([1, 2, 3, 4])); // 結果は"01,2,3,4"
となる。[1, 2, 3, 4]という配列オブジェクトはsum()には1つの引数として渡されるため、valueOf()ではなくtoString()が実行されて文字列として評価されてしまう。
こういった場合にはapplyをつかうと便利
alert(sum.apply(null, [1, 2, 3, 4])); // 結果は10
ちなみに第1引数には任意のオブジェクトを渡すことができ、関数本体の中からthisキーワードで参照することができる。
ならば、多重配列でも同じように解けるか言うと、
alert(sum.apply(null, [1, 2, [3, 4], 6, [7, 8, [9]], 10])); // 結果は"33,467,8,910"
と、最初の1, 2は計算されたものの次の要素は[3, 4]のため、文字列で評価され、以降は上手くいかない。
という訳で、オブジェクトの型に合わせて数値変換を試みるsum_flex()を作る
function sum_flex() { var total = 0; var element; for (var i = 0; i < arguments.length; i++){ element = arguments[i]; switch (typeof element){ case "number": n = element; break; case "object": if (element instanceof Array){ n = sum_flex.apply(null, element); } else { n = element.valueOf(); } break; } total += n; } return total; }
再帰呼び出しを使う事で、
alert(sum_flex([1, 2, [3, 4], 6, [7, 8, [9]], 10])); // 結果は55 alert(sum_flex.apply(null, [1, 2, [3, 4], 6, [7, 8, [9]], 10])); // 結果は55。もちろん上手く行く
と引数が配列だったらapply()を再帰呼び出しすることで、多重配列でも綺麗に解けるようになる。
実際にはあまり使わないかもしれないけど、結構柔軟。