メソッドのオーバーロード

後輩がちょっとはまっていたので。
javaなら以下のように引数の数が違う同名メソッドが定義できます。オーバーロードってやつです。

public int total(int[] ary);
public int total(int[] ary, boolean isInclude);

これと同じことがjavascriptでも出来るか、というのがポイント。

function SOMECLASS = function(){};
SOMECLASS.prototype.total = function(ary) {
  alert('引数1つ');
};
SOMECLASS.prototype.total = function(ary, isInclude) {
  alert('引数2つ');
};

このSOMECLASSをnewしてtotal(ary)の方を実行すると何が起きるか。
答えは「引数2つ」の方が画面に表示されます。

なぜか

javascript連想配列のお化けだと知っていれば簡単に分かります。そうです、連想配列の場合同じキーで違う値は登録できず、後勝ちで上書きされるからなのです。今回の問題は、以下を実行するとvalue2が出力されるのと同じ原理です。

  var hash = {};
  hash['key1'] = 'value1';
  hash['key1'] = 'value2';
  alert(hash['key1']);

つまり、javascriptではオーバーロードはできない、ってことです。

もうひとつの疑問

しかし、もうひとつ疑問が生じます。引数を2つ必要とするtotalメソッドが実際の関数なのに、呼び出し側は引数を1つしか指定せずに呼び出しました。「そんな関数ありません」といったエラーが出力されてもおかしくないのですが、画面には「引数2つ」と表示されることからどうやら正しく呼び出せているようです。コンパイラ言語なら当然エラーと出てしかるべきなので、javaに馴染んでいると戸惑うのも無理はありません。以下の例を見てみましょう。

function hoge() {
  alert('hoge');
}
function fuga(a,b,c) {
  alert('fuga');
}

hoge('hello', 'morning', 'bye');
fuga();

これらはエラーにはならずに、呼び出せるのです。つまりjavascriptの場合、呼び出し側は関数名さえあっていれば引数はでたらめでも実行可能なのです!私もはじめて知ったときはびっくりでした。ただし当然ながら、fuga関数の中でb変数を利用するようなプログラムを書いていたらbは「undefined」のためエラーが出ます。


なお、関数の中から引数を取得するには、argumentsオブジェクトからも取得することが出来ます。