-1

それぞれのタイプを判別できるように、関数オブジェクトのパラメーターを判別する方法を見つけようとしています。

Params.prototype.getParams = function (fn) {
   var a = fn.length;
   console.log("Args: " + a);

   for (var i = 0; i < a; i++) {
      // This is where I want to print the type
      console.log("Arg[" + i + "] type is: " + typeof(fn.arguments[i]));
   }
}

次に、次のようないくつかの関数(任意のJS関数である可能性があります)を定義すると、次のようになります。

function callback1("one") {}
function callback2("one", 2) {}
function callback3(1, "two", []) {}

後でそれぞれを呼び出す場合:

var params = new Params();

params.getParams(callback1);
params.getParams(callback2);
params.getParams(callback3);

各関数インスタンスの各パラメータタイプを把握したいと思います。私はそれをグーグルで検索し、SOで検索しましたが、役立つものは何も見つかりません。'長さ'がわかっている場合、なぜパラメータもわからないのかわかりません。

更新-2013.02.1917:41

はい、上記のコードに潜在的なエラーがあることは知っています。読みやすくするためにコードを削除しました。

これが私が達成しようとしていたことです:

私はこの(興味深い)記事を読んでいました: JavaScript関数のオーバーロード

Javaから来て、純粋主義者である私は、メソッドのオーバーロードの実験を始めたかったのです(くそー、JSがどれほど原始的であるか信じられません)。

オーバーロードされた関数を呼び出す必要がある「解決」の代わりにパラメーター型を使用する方法に「関数カウント」方法を置き換えて、記事の例を「強化」したいと思いました。これは、私の例では「fn」のパラメータタイプを実際に知っている場合にのみ実行できるようです。

4

5 に答える 5

4

関数パラメーターにはタイプがありません。

function fun(a,b,c) {... }

JavaScriptでは、任意の変数または関数パラメーターに、任意のタイプのオブジェクトまたはプリミティブを含めることができます。

それを行う唯一の方法は、実行時にを使用してチェックすることですarguments

function callback3(a,b,c) {
    if (typeof a != 'string') {
      throw new Error('callback3 expects a string for its first argument');
    }
}

タイプチェックをしたいように見えるので、次のようなものでこれを抽象化できます

function checkParams(args, types) {
    if (args.length != types.length) {
        throw new Error('Invalid number of arguments passed');
    }
    for (var i=0; i < args.length; i ++) {
        if (typeof args[i] != types[i]) {
            throw new Error('Argument number '+ i +' has wrong type'); 
        }
    }
}

function callback3(a,b,c) {
    checkParams(arguments, ['string', 'number', 'object') );
    // rest of the code
} 
于 2013-02-19T22:20:05.303 に答える
1

関数パラメーターには型がありません。オーバーロードのようなものが必要な場合は、自分で実装する必要があります。

これを使用する最も簡単な方法は、getterをオーバーロードすることです。また、jQueryのようなsetterメソッドは、そのval()関数や他の多くの関数に対して実行します。何も渡さない場合は値を取得し、渡す場合は値を設定します。ジョン・レシグが提案したものとは少し違うものを書きました。このように、2つの例を見てみましょう。

重要なことは、パラメーターのタイプを取得することはできず、関数定義で宣言されたパラメーターの数だけを取得できることです。

function overload(/*fun1, fun2, fun3... */) {
    var overloadedFuns = arguments;
    return function() {
        var argCount = arguments.length;
        for (var i=0; i < overloadedFuns.length; i++) {
           if (overloadedFuns[i].length === argCount) {
               return overloadedFuns[i].apply(this, arguments);
               break;
           }
        }
    }
}


var obj = {
  _val = 0;
  val: overload(
      // This will get called when called with no arguments
      function() {
          return this._val;
      },
      // This will get called when called with one arguments
      function(val){
          this._val = val;
      }
  )
}

console.log( obj.val() ); // Outputs 0
obj.val(5); // Sets it to 5
console.log( obj.val() ); // Outputs 5

タイプを追加することで、同様の概念を導入できます。ただし、関数定義から型を推測することはできないため、その情報を自分で追加する必要があります

例: http: //jsfiddle.net/UPuwE/1/

/**
 * @param {object[]} fnDefs, Each object should contain a paramList and a fn
 *  {paramMap: ["string"], fn: function() {myString}}
 *
 */
function overload(fnDefs) {

    function matches(arr1, arr2) {
        if (arr1.length !== arr2.length) {
            return false;
        }
        for (var i=0; i < arr1.length; i++) {
            if (arr1[i] !== arr2[i]) {
                return false;
            }
        }
        return true;
    }

    return function() {
        var types = [];
        for (var i =0; i < arguments.length; i++) {
            types.push(typeof arguments[i]);
        }
        for (var i=0; i < fnDefs.length; i++) {
            if (matches(types, fnDefs[i].paramMap)) {
                return fnDefs[i].fn.apply(this, arguments);
            }
        }
    }
}


var obj = {
    _val: 0,
    val: overload([
        {
            paramMap: ['string'],
            fn: function(str) {
                this._val = str;
            }
        },

        {
            paramMap: ['object'],
            // If an object is passed in, grab the string from its 
            // str property or by calling the toString() method;
            fn: function(obj) {
                this._val = obj.str || obj.toString();
            }
        },
        {
            paramMap: [],
            // Getter
            fn: function(obj) {
                return this._val;
            }
        }
    ])
};

obj.val('34');
console.log( obj.val() );

obj.val({str: '35'});
console.log( obj.val() );

obj.val( {toString: function(){return '36';} } );
console.log( obj.val() );

この例が、実行時に多くのオーバーヘッドがあることを示していることを願っています。そのため、ほとんどのライブラリはそれを使用しません。

于 2013-02-20T01:08:26.603 に答える
0

arguments変数をお探しですか?

function sayHi(name) {console.log(arguments)}

    sayHi('hackNightly')
>>> ['hackNightly']

引数がある場合は、引数をループしてtypeOf()などを使用して型チェックを行うことができるようです。

于 2013-02-19T22:17:04.983 に答える
0

関数オブジェクトは引数を格納しなくなり、varを使用して関数呼び出し内で直接使用できるようになりますarguments

http://www.sitepoint.com/arguments-a-javascript-oddity/

  //try this instead
  console.log("Arg[" + i + "] type is: " + typeof(arguments[i]));
于 2013-02-19T22:20:24.570 に答える
0

1時間の余裕があったので、「フアンメンデス」と「システム」の両方から受け取ったさまざまな提案を実装してみようと思いました。

以下は単なる実用的な例です(最適化されていない、ベンチマークされていない、クリーンアップされていない)ので、進行中と考えてください。他のことをする前に、いくつかのベンチマークを実行して、最終的にどのような「肥大化」が発生するかを確認したいと思います。

誰かがこれに何か問題があると思ったら、建設的な批判をしてください!

function Overload() {
    // Empty for now!
}

Overload.prototype.link = function (object, method) {   
    console.log("Creating dispatch method '" + method + "()'");

    object.prototype[method] = function () {
        var target = method + "_";

        console.log("Invoked dispatch method '" + method + "()'...");

        for (var i=0; i < arguments.length; i++) {
            target += (typeof arguments[i]).substring(0, 1);
        }

        console.log("Resolved target as '" + target + "'");

        if (typeof object.prototype._overloaded[target] !== "undefined") {
            console.log("Dispatching to overloaded method: '" + target + "'");
            return object.prototype._overloaded[target].apply(object, arguments);
        } else {
            console.log("Method not found: '" + method + "('" + target + "')'");
            //throw "Exception ...";
        }
    }
}

次の関数は、オブジェクト上の他のすべての関数をオーバーロードするために使用されます。

Overload.prototype.overload = function (object, method, fn, params) {
    var target = method + "_" + params;

    console.log("Overloading method '" + method + "()' to '" + method + "('" + params + "')'");

    if (typeof object === "undefined") {
        console.log("Object doesn't exist!");
    }

    if (typeof object.prototype[method] === "undefined") {
        this.link(object, method);
    }

    if (typeof object.prototype._overloaded === "undefined") {
        console.log("Creating '[obj].prototype._overloaded' property");
        object.prototype._overloaded = {};
    }

    if (typeof object.prototype._overloaded[target] === "undefined") {
        //console.log("Assigning overload function as target '" + method + "('" + params + "')'");
        object.prototype._overloaded[target] = fn;
    } else {
        console.log("Definition for '" + method + "('" + params + "')' already eixsts!");
    }

    return fn;
}

次に、オーバーロードされた関数を本質的に「モック」するいくつかのサンプル関数を定義します。

function fn1(one) {
    console.log("Invoked function 1: " + one);
}

function fn2(one, two) {
    console.log("Invoked function 2: " + one + ", " + two);
}

function fn3(one, two, three) {
    console.log("Invoked function 3: " + one + ", " + two + ", " + three);
}

function fn4(one, two, three) {
    console.log("Invoked function 4: " + one + ", " + two);
}

function fn5(one, two, three) {
    console.log("Invoked function 5: " + one + ", " + two);
}

これを使用してテストを実行します。

function testMethodOverloading() {
    console.log("Testing method overloading!");

    var ov = new Overload();

    function OBJ() {}

    console.log("--");

    ov.overload(OBJ, "name", fn1, 's');
    ov.overload(OBJ, "name", fn2, 'sn');
    ov.overload(OBJ, "name", fn3, 'sns');
    ov.overload(OBJ, "name", fn4, 'ss');
    ov.overload(OBJ, "name", fn5, 'nn');

    console.log("--");

    var obj = new OBJ();

    obj.name("one");
    obj.name("two", 1);
    obj.name("three", 2, "four");
    obj.name("five", "six");
    obj.name(3, 4);
}

これは、上記のテストを実行して得た出力です。

Overloading method 'name()' to 'name('s')'
Creating dispatch method 'name()'
Creating '[obj].prototype._overloaded' property
Overloading method 'name()' to 'name('sn')'
Overloading method 'name()' to 'name('sns')'
Overloading method 'name()' to 'name('ss')'
Overloading method 'name()' to 'name('nn')'
--
Invoked dispatch method 'name()'...
Resolved target as 'name_s'
Dispatching to overloaded method: 'name_s'
Invoked function 1: one
Invoked dispatch method 'name()'...
Resolved target as 'name_sn'
Dispatching to overloaded method: 'name_sn'
Invoked function 2: two, 1
Invoked dispatch method 'name()'...
Resolved target as 'name_sns'
Dispatching to overloaded method: 'name_sns'
Invoked function 3: three, 2, four
Invoked dispatch method 'name()'...
Resolved target as 'name_ss'
Dispatching to overloaded method: 'name_ss'
Invoked function 4: five, six
Invoked dispatch method 'name()'...
Resolved target as 'name_nn'
Dispatching to overloaded method: 'name_nn'
Invoked function 5: 3, 4 

だから、私が期待した/望んでいたようにそれは間違いなく実行されます!しかし、どのようなベンチマークが得られるのでしょうか。次に、参照されている記事のベンチマークの範囲内にいるかどうかを確認するためにそれを実行します(つまり、すべてのログを削除した後)。一般的な考え方がわかったら、結果を投稿します。

于 2013-02-20T22:28:46.420 に答える