5

JavaScript で関数を呼び出して、パラメーターを渡さなかった場合、何も起こりません。

これにより、コードのデバッグが難しくなるため、その動作を変更したいと考えています。

引数が JavaScript 関数に送信されていないかどうかを判断する最善の方法を見てきまし たが、入力されたコードの行数が一定のソリューションが必要です。各関数に余分なコードを入力しません。

(「ファーストクラス」) Function オブジェクトのコンストラクターを変更することにより、すべての関数のコードにそのコードを自動的にプレフィックスとして付けることを考えました。

JavaScript でのコンストラクターの変更に触発され て、次のように Function オブジェクトのコンストラクターを変更できるかどうかを最初にテストしました。

function Function2 () {
    this.color = "white";
}

Function.prototype = new Function2();
f = new Function();
alert(f.color);

ただし、「白」ではなく「未定義」と警告するため、機能していないため、この手法については詳しく調べていません。

任意のレベルでこの問題の解決策を知っていますか? JavaScript の内臓をハッキングすることは問題ありませんが、不足している引数を見つける方法に関するその他の実用的なヒントも問題ありません。

4

4 に答える 4

10

関数で特定の引数を渡す必要がある場合は、関数の検証の一環として、特にそれらの引数を確認する必要があります。

多くのライブラリは、渡されないデフォルトの引数の動作に依存しているため(jQueryがスコープ変数Functionに何も渡さないなど)、オブジェクトを拡張することは最善の方法ではありません。undefined

私がよく使う2つのアプローチ:

1)関数が機能するには引数が必要です

var foo = function (requiredParam) {
    if (typeof requiredParam === 'undefined') {
        throw new Error('You must pass requiredParam to function Foo!');
    }

    // solve world hunger here
};

2)引数は渡されませんが、デフォルトで何かに設定できます(jQueryを使用)

var foo = function (argumentObject) {
    argumentObject = $.extend({
        someArgument1: 'defaultValue1',
        someArgument2: 'defaultValue2'
    }, argumentObject || {});

    // save the world from alien invaders here
};
于 2012-06-27T12:47:54.043 に答える
2

他の人が言ったように、これをしない理由はたくさんありますが、私はいくつかの方法を知っているので、その方法を説明します! 科学について!

これはGabyから盗まれた最初のものです。彼に賛成票を投じてください! これがどのように機能するかの大まかな概要は次のとおりです。

//example function
function thing(a, b, c) {

}

var functionPool = {} // create a variable to hold the original versions of the functions

for( var func in window ) // scan all items in window scope
{
  if (typeof(window[func]) === 'function') // if item is a function
  {
    functionPool[func] = window[func]; // store the original to our global pool
    (function(){ // create an closure to maintain function name
         var functionName = func;
         window[functionName] = function(){ // overwrite the function with our own version
         var args = [].splice.call(arguments,0); // convert arguments to array
         // do the logging before callling the method
         if(functionPool[functionName].length > args.length)
              throw "Not enough arguments for function " + functionName + " expected " + functionPool[functionName].length + " got " + args.length;                     
         // call the original method but in the window scope, and return the results
         return functionPool[functionName].apply(window, args );
         // additional logging could take place here if we stored the return value ..
        }
      })();
  }
}

thing(1,2 ,3); //fine
thing(1,2); //throws error

2 番目の方法:

これを行う別の方法がありますが、詳細を正確に思い出せません。基本的にはオーバーライドしFunction.prototype.callます。しかし、この質問にあるように、これには無限ループが含まれます。したがって、呼び出すには汚染されていない Function オブジェクトが必要です。これは、変数を文字列にeval変換し、汚染されていないコンテキストで関数を呼び出すというトリックによって行われます! Web の黎明期からの方法を示す非常に優れたスニペットがありますが、残念ながら現時点では見つかりません。変数を適切に渡すために必要なハックがあり、実際にはコンテキストを失う可能性があると思うので、かなり壊れやすいです。

それでも、述べたように、他のすべての回答のように、仲間のプログラマーを信頼するか、デフォルトを提供するかのいずれかで、javascriptにその性質に反することを強制しようとしないでください。

于 2012-06-27T13:38:11.293 に答える
1

デコレータパターンを使用できます。次のデコレータを使用すると、渡す必要のある引数の最小数と最大数、およびオプションのエラーハンドラを指定できます。

/* Wrap the function *f*, so that *error_callback* is called when the number
   of passed arguments is not with range *nmin* to *nmax*. *error_callback*
   may be ommited to make the wrapper just throw an error message.
   The wrapped function is returned. */
function require_arguments(f, nmin, nmax, error_callback) {
    if (!error_callback) {
        error_callback = function(n, nmin, nmax) {
            throw 'Expected arguments from ' + nmin + ' to ' + nmax + ' (' +
                  n + ' passed).';
        }
    }
    function wrapper() {
        var n_args = arguments.length;
        console.log(n_args, nmin, nmax);
        console.log((nmin <= 0) && (0 <= nmax));
        if ((nmin <= n_args) && (n_args <= nmax)) {
            return f.apply(this, arguments);
        }
        return error_callback(n_args, nmin, nmax);
    }
    for (e in f) {
        wrapper[e] = f[e];
    }
    return wrapper;
}


var foo = require_arguments(function(a, b, c) {
    /* .. */
}, 1, 3);
foo(1);
foo(1, 2);
foo(1, 2, 3);
foo(1, 2, 3, 4); // uncaught exception: Expected arguments from 1 to 3 (4 passed).
foo(); // uncaught exception: Expected arguments from 1 to 3 (0 passed).
于 2012-06-27T12:48:26.450 に答える
1

Pythonのデコレータのようなものを模倣することができます。これには、追加の行ではありませんが、関数ごとに追加の入力が必要です。

function force(inner) {
    return function() {
        if (arguments.length === inner.length) {
            return inner.apply(this, arguments);
        } else {
            throw "expected " + inner.length +
                " arguments, got " + arguments.length;
        }
    }
}

var myFunc = force(function(foo, bar, baz) {
    // ...
});

あなたは基本的に言語をいじっているので、一般的にこれは悪い考えのように聞こえます。あなたは本当に頻繁に議論を渡すことを忘れていますか?

于 2012-06-27T12:48:35.270 に答える