代码之家  ›  专栏  ›  技术社区  ›  smack0007

处理带有命名参数和普通参数的调用函数的javascript

  •  3
  • smack0007  · 技术社区  · 14 年前

    如果我有这个功能:

    function(foo, bar, baz);
    

    我想同时考虑命名参数和普通函数调用,处理这个问题的最佳方法是什么?在PHP中,您可以将变量提取到本地名称空间中,但据我所知,在JavaScript中处理这一点的唯一方法是分别处理这两个场景。我给出了下面的代码示例:

    function(foo, bar, baz)
    {
        if(typeof(foo) == 'object') // Named args
        {
            alert(foo.foo);
            alert(foo.bar);
            alert(foo.baz);
        }
        else
        {
            alert(foo);
            alert(bar);
            alert(baz);
        }
    }
    
    myFunc('a', 'b', 'c');
    myFunc({ foo: 'a', bar: 'b', baz: 'c' });
    

    有谁能教我javascriptfu的方法呢?

    3 回复  |  直到 14 年前
        1
  •  3
  •   jwueller    14 年前

    因为您不能动态访问本地作用域(没有邪恶 eval )您应该考虑以下方法:

    var myFunc = function (foo, bar, baz) {
        if (typeof(foo) === 'object') {
            bar = foo.bar;
            baz = foo.baz;
            foo = foo.foo; // note: foo gets assigned after all other variables
        }
    
        alert(foo);
        alert(bar);
        alert(baz);
    };
    

    只需手动将命名的参数转换为正则变量。之后,您的代码将在两种情况下运行,而不做任何更改。

        2
  •  1
  •   wnrph    14 年前

    优雅地做:

    var myFunc = (function (foo, bar, baz) {
                       // does whatever it is supposed to do
                   }).
        withNamedArguments({foo:"default for foo", bar:"bar", baz:23 });
    
    myFunc({foo:1}); // calls function(1, "bar", 23)
    myFunc({});  // calls function("default for foo", "bar", 23);
    myFunc({corrupt:1}); // calls function({corrupt:1})
    myFunc([2,4], 1);  //calls function([2,4], 1)
    

    即使这个也行

    Array.prototype.slice =
        Array.prototype.slice.withNamedArguments({start:0, length:undefined});
    
    [1,2,3].slice({length:2}) //returns [1,2]
    [1,2,3].slice(1,2) //returns [2,3]
    

    …或者在这里,parseint()。

    parseInt = parseInt.withNamedArguments({str:undefined, base:10});
    parseInt({str:"010"}); //returns 10
    

    只需增强函数对象:

    Function.prototype.withNamedArguments = function( argumentList ) {
        var actualFunction = this;
        var idx=[];
        var ids=[];
        var argCount=0;
        // construct index and ids lookup table
        for ( var identifier in argumentList ){
            idx[identifier] = argCount;
            ids[argCount] = identifier;
    
            argCount++;
        }
    
        return function( onlyArg ) {
            var actualParams=[];
            var namedArguments=false;
    
            // determine call mode
            if ( arguments.length == 1 && onlyArg instanceof Object ) {
                namedArguments = true;
                // assume named arguments at the moment
                onlyArg = arguments[0];
                for ( name in onlyArg )
                    if (name in argumentList ) {
                        actualParams[idx[name]] = onlyArg[name];
                    } else {
                        namedArguments = false;
                        break;
                    }
            }
            if ( namedArguments ) {
                // fill in default values
                for ( var i = 0; i < argCount; i++ ) {
                    if ( actualParams[i] === undefined )
                        actualParams[i] = argumentList[ids[i]];
                }
            } else 
                actualParams = arguments;
    
            return actualFunction.apply( this, actualParams );
        };
    };
    
        3
  •  0
  •   annakata    14 年前

    这总是很尴尬,也不是很严格,但是检查参数是否缺少数据要比检查特定的积极期望(尤其是对象类型)安全得多。

    下面的一些变化,这里的策略是将DTO样式输入转换为命名的参数样式输入(相反也是合理的,但我发现不太明显)。这个策略的优点是,一旦您通过了这个翻译块,其余的代码就不关心您是如何到达那里的。

    // translate to named args - messy up front, cleaner to work with
    function(foo, bar, baz) 
    {
        // Opt 1: default to named arg, else try foo DTO
        bar = (typeof(bar) != 'undefined' ? bar : foo.bar);
    
        // Opt 2: default to named arg, else check if property of foo, else hard default (to null)
        baz = (typeof(baz) != 'undefined' ? baz : typeof(foo.baz) != 'undefined' ? foo.baz : null);
    
        // the first argument is always a problem to identify in itself
        foo = (foo != null ? typeof(foo.foo) != 'undefined' ? foo.foo : foo : null);
    }
    
    // translate to object - cleaner up front, messier to work with
    function(foo, bar, baz) 
    {
        var input = (typeof(foo.foo) != 'undefined' ? foo : { 'foo' : foo, 'bar' : bar, 'baz' : baz });
    }
    

    第一个arg(这里是foo)始终是一个问题,因为您希望它处于两个复杂状态之一(其中其他arg始终是单个复杂状态或未定义),并且在处理完所有其他arg之前无法处理它,因为显然,一旦您更改了它,它就不可靠了o用它来初始化其他任何东西。