2010-11-12 33 views
3

如果我具备的功能:JavaScript中处理调用带有命名参数数量的功能和普通

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' }); 

任何JavaScript的大师谁可以教我的javascriptFu的方式吗?

回答

3

既然你不能访问动态局部范围内(不恶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); 
}; 

您只需翻译命名的参数传递给手动普通变量。之后,您的代码将在两种情况下运行而不发生任何更改。

+0

这实际上是我在思考我的问题一段时间后得出的结论。 – smack0007 2010-11-12 09:12:21

+0

@ smack0007:这是迄今为止最简单的解决方案。你可以(当然)以相反的方式做到这一点:确保所有东西都可以通过对象访问。不过,这可能会更冗长些。 – jwueller 2010-11-12 09:59:03

0

这总是很尴尬,并不是很严格,但检查缺少数据的参数比特定的积极期望更安全,特别是对象类型。

下面的一些变化,这里的策略是将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 }); 
} 

的第一个参数(FOO这里)始终是一个问题,因为你希望它是在两个复杂的国家之一(其中其他ARG游戏总是一个复杂的状态或不确定的),你不能处理它,直到你已经处理了所有其他的参数,因为显然一旦你改变了它,用它来初始化其他任何东西都是不可靠的。

1

优雅做它:

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); 
    }; 
}; 
相关问题