26

私はJavascriptコードで以下のようにメソッドのオーバーロードを使用しています。

function somefunction()
{
    //1st function
}

function somefunction(a)
{
   //2nd function
}

function somefunction(a,b)
{
   //3rd function
}

somefunction(); // function call goes here

私が理解していないのは、somefunction()JavaScriptを呼び出すと1番目の関数を呼び出す必要があるということですが、問題はjavascriptが実際に3番目の関数を呼び出すことです。何故ですか?1番目と2番目の関数を呼び出すにはどうすればよいですか?これの理由は何ですか?Javascriptでメソッドのオーバーロードを実装する適切な方法はありますか?業界標準は何ですか?

4

12 に答える 12

44

JavaScript はメソッドのオーバーロードをサポートしていません (Java または類似のものと同様)。3 番目の関数は以前の宣言を上書きします。

arguments代わりに、 objectを介して可変引数をサポートします。あなたができる

function somefunction(a, b) {
    if (arguments.length == 0) { // a, b are undefined
        // 1st body
    } else if (arguments.length == 1) { // b is undefined
        // 2nd body
    } else if (arguments.length == 2) { // both have values
        // 3rd body
    } // else throw new SyntaxError?
}

etc をチェックすることもできます。typeof a == "undefined"これにより、 を呼び出すことがsomefunction(undefined)できarguments.lengthます1。これにより、変数が空の可能性がある場合など、さまざまなパラメーターを使用して簡単に呼び出すことができる場合があります。

于 2012-10-02T16:43:04.440 に答える
9

JSはundefined、提供されていないパラメーターを渡します。オーバーロードのようなものが必要な場合は、以下のコードのようなことを行う必要があります。

function someFunction(a, b) {
    if (typeof a === 'undefined') {
        // Do the 0-parameter logic
    } else if (typeof b === 'undefined') {
        // Do the 1-parameter logic
    } else {
        // Do the 2-parameter logic
    }
}
于 2012-10-02T16:45:25.983 に答える
8

somefunction新しい宣言ごとに変数を消去しているだけです。

これは

   window.somefunction = function(...
   window.somefunction = function(...
   window.somefunction = function(...

Javascript はメソッドのオーバーロードを提供しません。

適切な方法は次のいずれかです。

  • 3 番目の関数を定義し、どのパラメーターが定義されているかをテストする
  • パラメータを含むオブジェクトを 1 つだけ渡す (実際には違いはありませんが、よりクリーンです)
于 2012-10-02T16:42:59.667 に答える
4

JavaScriptでメソッドをオーバーロードすることはできません。javascriptでは、関数は変数に格納されます。グローバル変数はウィンドウオブジェクトに保存されます。同じ名前(排他的キーハッシュ)を持つオブジェクトごとに1つのプロパティのみを持つことができます。

できることは、最も多くのパラメーターを使用して定義を定義し、渡されたパラメーターの数を確認することです。

function Test(a, b, c)
{
    if(typeof a == 'undefined') 
    {
        a = 1;
    }

    if(typeof b == 'undefined') 
    {
        b = "hi";
    }

    if(typeof c == 'undefined') 
    {
        c = Date.Now;
    }
}

Test()を呼び出すと、呼び出したように動作しますTest(1, "hi", Date.Now)

于 2012-10-02T16:47:31.113 に答える
3

ここで説明されているこの問題に対するエレガントな解決策を開発しようとしました。デモはこちらからご覧いただけます。使用法は次のようになります。

var out = def({
    'int': function(a) {
        alert('Here is int '+a);
    },

    'float': function(a) {
        alert('Here is float '+a);
    },

    'string': function(a) {
        alert('Here is string '+a);
    },

    'int,string': function(a, b) {
        alert('Here is an int '+a+' and a string '+b);
    },
    'default': function(obj) {
        alert('Here is some other value '+ obj);
    }

});

out('ten');
out(1);
out(2, 'robot');
out(2.5);
out(true);

これを達成するために使用される方法:

var def = function(functions, parent) {
 return function() {
    var types = [];
    var args = [];
    eachArg(arguments, function(i, elem) {
        args.push(elem);
        types.push(whatis(elem));
    });
    if(functions.hasOwnProperty(types.join())) {
        return functions[types.join()].apply(parent, args);
    } else {
        if (typeof functions === 'function')
            return functions.apply(parent, args);
        if (functions.hasOwnProperty('default'))
            return functions['default'].apply(parent, args);        
    }
  };
};

var eachArg = function(args, fn) {
 var i = 0;
 while (args.hasOwnProperty(i)) {
    if(fn !== undefined)
        fn(i, args[i]);
    i++;
 }
 return i-1;
};

var whatis = function(val) {

 if(val === undefined)
    return 'undefined';
 if(val === null)
    return 'null';

 var type = typeof val;

 if(type === 'object') {
    if(val.hasOwnProperty('length') && val.hasOwnProperty('push'))
        return 'array';
    if(val.hasOwnProperty('getDate') && val.hasOwnProperty('toLocaleTimeString'))
        return 'date';
    if(val.hasOwnProperty('toExponential'))
        type = 'number';
    if(val.hasOwnProperty('substring') && val.hasOwnProperty('length'))
        return 'string';
 }

 if(type === 'number') {
    if(val.toString().indexOf('.') > 0)
        return 'float';
    else
        return 'int';
 }

 return type;
};
于 2013-04-10T01:17:36.837 に答える
3

JavaScript では、任意の型の任意の数のパラメーターを渡すことができるため、実際の関数のオーバーロードはありません。ベストプラクティスは、次のような関数を作成することです: myfunc(opt)

{
// with opt = {'arg1':'a1','arg2':2, etc}, then check your opt inside of the function
}
于 2012-10-02T16:48:34.490 に答える
3

私が理解していないのは、somefunction() を呼び出す場合、JavaScript は最初の関数を呼び出す必要がありますが、問題は JavaScript が実際に 3 番目の関数を呼び出すことです。

これは予期される動作です。

何故ですか ?

問題は、JavaScript がメソッドのオーバーロードをネイティブにサポートしていないことです。そのため、同じ名前の 2 つ以上の関数を認識または解析した場合、最後に定義された関数を考慮して、以前の関数を上書きします。

何故ですか ?1番目と2番目の関数を呼び出すにはどうすればよいですか? これの理由は何ですか?

ほとんどの場合に適していると思う方法の1つは次のとおりです-

メソッドがあるとしましょう

function foo(x)
{
} 

JavaScript では不可能なメソッドをオーバーロードする代わりに、新しいメソッドを定義できます。

fooNew(x,y,z)
{
}

次に、最初の関数を次のように変更します -

function foo(x)
{
  if(arguments.length==2)
  {
     return fooNew(arguments[0],  arguments[1]);
  }
} 

このようなオーバーロードされたメソッドが多数ある場合は、ステートメントswitchだけでなく使用を検討してください。if-else

メソッドのオーバーロードを行う適切な方法はありますか? 業界標準は何ですか?

JavaScriptでメソッドのオーバーロードを行うための標準や、より実績のある方法はありません。プログラミング設計に最も適したものを行う必要があります。引数の長さを単純に切り替えて、型が未定義ではないことを確認するだけで十分です。

于 2014-09-13T06:51:55.267 に答える
2

引数オブジェクトは、メソッドのオーバーロードのような概念を作成するために使用されます。

引数は、関数実行コンテキスト内でのみ使用できる特別なタイプのオブジェクトです。

arguments.lengthプロパティは、関数に渡されるパラメーターの数を識別するために使用されます。

偽のメソッドのオーバーロードを作成するために、ファースト クラス関数をより適切に使用できます。完全な概念は、私自身の Web サイトで説明されています: JavaScript での関数のオーバーロード

于 2017-10-04T17:30:15.343 に答える
0

私はこれをいじり、カスタムクラスに対してこれを問題なく機能させることができました。

let overloadTest = overload(
    [String], function(value) {
        console.log('we got a string', value);
    },
    [Number], function(value) {
        console.log('we got a number', value);
    },
    [String, Number], function(s, n) {
        console.log('we got a string AND a number', s, n);
    }
    [MyCustomClass], function(value) {
        console.log('we got a MyCustomClass instance', value);
    }
);

このoverload実装では:

function overload(...overloads) {
    const f = function(...args) {
        let constructorArray = args.map(arg => arg.constructor);
        let implIndex = f.overloads.findIndex(sig => {
            return constructorArray.length === sig.length &&
                constructorArray.every((o,i) => o === sig[i])
            ;
        }) + 1;
        if (implIndex > 0 && typeof(f.overloads[implIndex]) === 'function') {
            return f.overloads[implIndex].apply({}, args);
        } else {
            const message = "There is no implementation that matches the provided arguments.";
            console.error(message, constructorArray);
            throw Error(message);
        }
    };
    f.overloads = overloads;
    return f;
};

これはまだインスタンス メソッドでは機能しません。しかし、それは延長される可能性があります。

また、引数リストは (文字列ではなく) コンストラクターを直接参照します。つまり、必要に応じて追加の検証を拡張できます。たとえば、各引数の型が実際には関数/コンストラクターであることを確認しますoverload()。DI を実行する のバージョンを作成することも考えられます。overload()

于 2021-10-01T14:32:19.077 に答える