HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

メソッドのオーバーロードをしてみる

JavaScriptでは、関数の引数の型や個数をチェックしないため、いわゆるメソッドオーバーロードをすることはできない。(というのはどこかで書いた気がする⇒「関数のオーバーロードはできないよ - HHeLiBeXの日記 正道編」)

// !!!世の中、思い通りにはいかないよ!!!
function Hoge() { }
Hoge.prototype.fuga = function(str) {
    return 'string: ' + str;
}
Hoge.prototype.fuga = function(str1, str2) {
    return 'two strings: ' + str1 + ' and ' + str2;
}
alert(new Hoge().fuga('Hello')); // 'two strings: Hello and undefined'

この程度の処理なら、ひとつのメソッドの中で引数のチェックをすればよいのだが、規模が大きくなるとわけ分からなくなりそう。
ということで、ちょっともがいてみた(謎)。

// コンストラクタ。とりあえずやることはなし。
function Hoge() {
}
// public な fuga メソッド。引数に応じて適切なメソッド実体へ委譲。
Hoge.prototype.fuga = function() {
    if (arguments.length != 1) {
        throw {
            name: 'AssertionError',
            message: 'exactly one argument is required.'
        };
    }
    if (typeof arguments[0] === 'number') {
        return this.privateMethods['_fuga_number'](arguments[0]);
    } else if (typeof arguments[0] === 'string') {
        return this.privateMethods['_fuga_string'](arguments[0]);
    } else {
        throw {
            name: 'AssertionError',
            message: 'invalid argument ' + arguments[0] + ' (' + (typeof arguments[0]) + ')'
        };
    }
}
// オーバーロードするメソッドの実体
Hoge.prototype.privateMethods = Array();
//   Hoge.fuga(number)
Hoge.prototype.privateMethods['_fuga_number'] = function(num) {
    return 'number: ' + num + ' (' + (typeof num) + ')';
}
//   Hoge.fuga(string)
Hoge.prototype.privateMethods['_fuga_string'] = function(str) {
    return 'string: ' + str + ' (' + (typeof str) + ')';
}
  • test.html
<html>
    <head>
        <title>overload test</title>
        <script type="text/javascript" src="Hoge.js"></script>
        <script type="text/javascript">
            function Foo() {
            }
            function test(arg) {
                var hoge = new Hoge();
                try {
                    alert(hoge.fuga(arg));
                } catch (e) {
                    alert(e.name + ': ' + e.message);
                }
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="javascript:test(1)" value="「1」" />
        <input type="button" onclick="javascript:test('1')" value="「'1'」" />
        <input type="button" onclick="javascript:test(new Foo())" value="「new Foo()」" />
        <input type="button" onclick="javascript:test(null)" value="「null」" />
        <input type="button" onclick="javascript:test(false)" value="「false」" />
        <input type="button" onclick="javascript:test(true)" value="「true」" />
    </body>
</html>

これでnumberなのかstringなのかを気にせずに同じメソッド名で呼び出せる。
まぁ、これが「JavaScript: The Good Parts」的にいいのか悪いのかは知らないけど(ぉ

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス