如果我有这个功能:
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的方式?
答案 0 :(得分: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);
};
您只需手动将命名的args转换为常规变量。之后,您的代码将针对这两种情况运行而无需更改。
答案 1 :(得分: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对象:
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 );
};
};
答案 2 :(得分: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 });
}
第一个arg(这里的foo)总是一个问题,因为你希望它处于两个复杂状态之一(其他args总是一个复杂的状态或未定义),你不能处理它直到你&#39;已经处理了所有其他的args,因为很明显,一旦你改变了它,用它来初始化其他东西是不可靠的。