我有一个静态的javascript函数,可以使用1,2或3个参数:
function getData(id, parameters, callback) //parameters (associative array) and callback (function) are optional
我知道我总是可以测试给定参数是否未定义,但我怎么知道传递的是参数还是回调?
这样做的最佳方式是什么?
可传递的内容示例:
1:
getData('offers');
2:
var array = new Array();
array['type']='lalal';
getData('offers',array);
3:
var foo = function (){...}
getData('offers',foo);
4:
getData('offers',array,foo);
答案 0 :(得分:163)
您可以知道有多少arguments传递给您的函数,您可以检查您的第二个参数是否是函数:
function getData (id, parameters, callback) {
if (arguments.length == 2) { // if only two arguments were supplied
if (Object.prototype.toString.call(parameters) == "[object Function]") {
callback = parameters;
}
}
//...
}
您也可以这样使用arguments对象:
function getData (/*id, parameters, callback*/) {
var id = arguments[0], parameters, callback;
if (arguments.length == 2) { // only two arguments supplied
if (Object.prototype.toString.call(arguments[1]) == "[object Function]") {
callback = arguments[1]; // if is a function, set as 'callback'
} else {
parameters = arguments[1]; // if not a function, set as 'parameters'
}
} else if (arguments.length == 3) { // three arguments supplied
parameters = arguments[1];
callback = arguments[2];
}
//...
}
如果您有兴趣,请参阅John Resig的article,了解一种模拟JavaScript上方法重载的技巧。
答案 1 :(得分:74)
呃 - 这意味着你正在使用不正确顺序的参数来调用你的函数......我不推荐这样做。
我建议改为将一个对象传递给你的函数:
function getData( props ) {
props = props || {};
props.params = props.params || {};
props.id = props.id || 1;
props.callback = props.callback || function(){};
alert( props.callback )
};
getData( {
id: 3,
callback: function(){ alert('hi'); }
} );
好处:
缺点:
如果您别无选择,可以使用函数来检测对象是否确实是一个函数(参见上一个示例)。
注意:这是检测函数的正确方法:
function isFunction(obj) {
return Object.prototype.toString.call(obj) === "[object Function]";
}
isFunction( function(){} )
答案 2 :(得分:2)
因此,使用typeof运算符来确定第二个参数是数组还是函数。
这可以提供一些建议: http://www.planetpdf.com/developer/article.asp?ContentID=testing_for_object_types_in_ja
我不确定这是作品还是作业,所以我现在不想给你答案,但是typeof会帮助你确定它。
答案 3 :(得分:2)
您应该检查接收参数的类型。也许你应该使用arguments
数组,因为第二个参数有时可能是'参数',有时候'回调'并且命名它参数可能会产生误导。
答案 4 :(得分:2)
我知道这是一个非常古老的问题,但我最近处理过这个问题。让我知道您对此解决方案的看法。
我创建了一个实用程序,它允许我强烈地键入参数并让它们是可选的。您基本上将您的函数包装在代理中。如果你跳过一个参数,那就是 undefined 。如果你有多个相同类型的可选参数紧挨着它,它可能会变得古怪。 (可以选择传递函数而不是类型来执行自定义参数检查,以及为每个参数指定默认值。)
这是实现的样子:
function displayOverlay(/*message, timeout, callback*/) {
return arrangeArgs(arguments, String, Number, Function,
function(message, timeout, callback) {
/* ... your code ... */
});
};
为清楚起见,这是正在发生的事情:
function displayOverlay(/*message, timeout, callback*/) {
//arrangeArgs is the proxy
return arrangeArgs(
//first pass in the original arguments
arguments,
//then pass in the type for each argument
String, Number, Function,
//lastly, pass in your function and the proxy will do the rest!
function(message, timeout, callback) {
//debug output of each argument to verify it's working
console.log("message", message, "timeout", timeout, "callback", callback);
/* ... your code ... */
}
);
};
您可以在我的GitHub存储库中查看arrangeArgs代理代码:
https://github.com/joelvh/Sysmo.js/blob/master/sysmo.js
这是实用程序函数,其中一些注释是从存储库中复制的:
/*
****** Overview ******
*
* Strongly type a function's arguments to allow for any arguments to be optional.
*
* Other resources:
* http://ejohn.org/blog/javascript-method-overloading/
*
****** Example implementation ******
*
* //all args are optional... will display overlay with default settings
* var displayOverlay = function() {
* return Sysmo.optionalArgs(arguments,
* String, [Number, false, 0], Function,
* function(message, timeout, callback) {
* var overlay = new Overlay(message);
* overlay.timeout = timeout;
* overlay.display({onDisplayed: callback});
* });
* }
*
****** Example function call ******
*
* //the window.alert() function is the callback, message and timeout are not defined.
* displayOverlay(alert);
*
* //displays the overlay after 500 miliseconds, then alerts... message is not defined.
* displayOverlay(500, alert);
*
****** Setup ******
*
* arguments = the original arguments to the function defined in your javascript API.
* config = describe the argument type
* - Class - specify the type (e.g. String, Number, Function, Array)
* - [Class/function, boolean, default] - pass an array where the first value is a class or a function...
* The "boolean" indicates if the first value should be treated as a function.
* The "default" is an optional default value to use instead of undefined.
*
*/
arrangeArgs: function (/* arguments, config1 [, config2] , callback */) {
//config format: [String, false, ''], [Number, false, 0], [Function, false, function(){}]
//config doesn't need a default value.
//config can also be classes instead of an array if not required and no default value.
var configs = Sysmo.makeArray(arguments),
values = Sysmo.makeArray(configs.shift()),
callback = configs.pop(),
args = [],
done = function() {
//add the proper number of arguments before adding remaining values
if (!args.length) {
args = Array(configs.length);
}
//fire callback with args and remaining values concatenated
return callback.apply(null, args.concat(values));
};
//if there are not values to process, just fire callback
if (!values.length) {
return done();
}
//loop through configs to create more easily readable objects
for (var i = 0; i < configs.length; i++) {
var config = configs[i];
//make sure there's a value
if (values.length) {
//type or validator function
var fn = config[0] || config,
//if config[1] is true, use fn as validator,
//otherwise create a validator from a closure to preserve fn for later use
validate = (config[1]) ? fn : function(value) {
return value.constructor === fn;
};
//see if arg value matches config
if (validate(values[0])) {
args.push(values.shift());
continue;
}
}
//add a default value if there is no value in the original args
//or if the type didn't match
args.push(config[2]);
}
return done();
}
答案 5 :(得分:2)
我建议您使用ArgueJS。
您可以这样输入您的功能:
function getData(){
arguments = __({id: String, parameters: [Object], callback: [Function]})
// and now access your arguments by arguments.id,
// arguments.parameters and arguments.callback
}
我在您的示例中考虑过您希望id
参数为字符串,对吧?
现在,getData
需要String id
并且正在接受选项Object parameters
和Function callback
。您发布的所有用例都将按预期工作。
答案 6 :(得分:1)
您可以使用功能内的arguments object property。
答案 7 :(得分:1)
你是说你有这样的电话: getData(id,parameters); getData(id,callback)?
在这种情况下,你显然不能依赖位置,你必须依靠分析类型: getType()然后在必要时getTypeName()
检查有问题的参数是数组还是函数。
答案 8 :(得分:0)
我想你想在这里使用typeof():
function f(id, parameters, callback) {
console.log(typeof(parameters)+" "+typeof(callback));
}
f("hi", {"a":"boo"}, f); //prints "object function"
f("hi", f, {"a":"boo"}); //prints "function object"
答案 9 :(得分:0)
如果你的问题只是函数重载(你需要检查'参数'参数是'参数'而不是'回调'),我建议你不要打扰参数类型和
使用this approach。这个想法很简单 - 使用文字对象来组合你的参数:
function getData(id, opt){
var data = voodooMagic(id, opt.parameters);
if (opt.callback!=undefined)
opt.callback.call(data);
return data;
}
getData(5, {parameters: "1,2,3", callback:
function(){for (i=0;i<=1;i--)alert("FAIL!");}
});
答案 10 :(得分:0)
我想这可能是一个自我解释的例子:
function clickOn(elem /*bubble, cancelable*/) {
var bubble = (arguments.length > 1) ? arguments[1] : true;
var cancelable = (arguments.length == 3) ? arguments[2] : true;
var cle = document.createEvent("MouseEvent");
cle.initEvent("click", bubble, cancelable);
elem.dispatchEvent(cle);
}
答案 11 :(得分:-5)
你可以覆盖这个功能吗?这不起作用:
function doSomething(id){}
function doSomething(id,parameters){}
function doSomething(id,parameters,callback){}