Handling optional parameters in javascript
我有一个静态javascript函数,可以接受1、2或3个参数:
1 | function getData(id, parameters, callback) //parameters (associative array) and callback (function) are optional |
我知道我总是可以测试给定参数是否未定义,但是我如何知道传递的是参数还是回调?
最好的方法是什么?
可以传递的示例:
1:
1 | getData('offers'); |
2:
1 2 3 | var array = new Array(); array['type']='lalal'; getData('offers',array); |
三:
1 2 | var foo = function (){...} getData('offers',foo); |
4:
1 | getData('offers',array,foo); |
You can know how many arguments were passed to your function and you can check if your second argument is a function or not:
1 2 3 4 5 6 7 8 | 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对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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]; } //... } |
如果您感兴趣,请看一下JohnResig撰写的这篇文章,它介绍了一种在JavaScript上模拟方法重载的技术。
这意味着您正在用不正确顺序的参数调用函数…我不推荐。
我建议您将一个对象输入到您的函数中,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 | 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'); } } ); |
效益:
- 你不必考虑争论顺序
- 你不必检查类型
- 定义默认值比较容易,因为不需要进行类型检查
- 减少头痛。想象一下,如果添加了第四个参数,那么每次都必须更新类型检查,如果第四个参数或连续参数也是函数呢?
缺点:
- 重构代码的时间
如果您没有选择,您可以使用一个函数来检测一个对象是否确实是一个函数(参见上一个示例)。
注意:这是检测功能的正确方法:
1 2 3 4 5 | function isFunction(obj) { return Object.prototype.toString.call(obj) ==="[object Function]"; } isFunction( function(){} ) |
我建议你使用Arguejs。
您可以这样键入函数:
1 2 3 4 5 6 | function getData(){ arguments = __({id: String, parameters: [Object], callback: [Function]}) // and now access your arguments by arguments.id, // arguments.parameters and arguments.callback } |
我从你的例子中考虑过,你希望你的
我知道这是一个很古老的问题,但我最近处理过这个问题。让我知道你对这个解决方案的看法。
我创建了一个实用程序,它允许我强输入参数,并允许它们是可选的。您基本上将函数包装在代理中。如果跳过一个参数,它是未定义的。如果您旁边有多个具有相同类型的可选参数,这可能会变得很奇怪。(可以选择传递函数而不是类型来执行自定义参数检查,以及为每个参数指定默认值。)
实现如下所示:
1 2 3 4 5 6 | function displayOverlay(/*message, timeout, callback*/) { return arrangeArgs(arguments, String, Number, Function, function(message, timeout, callback) { /* ... your code ... */ }); }; |
为了清楚起见,下面是正在发生的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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
下面是实用程序函数,其中有些注释是从存储库中复制的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | /* ****** 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(); } |
您应该检查接收参数的类型。也许您应该使用
因此,使用typeof运算符来确定第二个参数是数组还是函数。
这可以给出一些建议:http://www.planetpdf.com/developer/article.asp?contentID=测试_-ja中的_-object_-types_
我不确定这是工作还是家庭作业,所以我现在不想给你答案,但类型将帮助你确定它。
Are you saying you can have calls like these:
getData(id, parameters);
getData(id, callback)?
In this case you can't obviously rely on position and you have to rely on analysing the type:
getType() and then if necessary getTypeName()
Check if the parameter in question is an array or a function.
您可以在函数内使用arguments对象属性。
我想这可能是一个不言自明的例子:
1 2 3 4 5 6 7 8 | 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); } |
如果您的问题只是函数重载(您需要检查"parameters"参数是否为"parameters",而不是"callback"),我建议您不要担心参数类型和使用这种方法。这个想法很简单-使用文本对象组合参数:
1 2 3 4 5 6 7 8 9 10 | 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!");} }); |
我想您要在这里使用typeof():
1 2 3 4 5 6 7 8 | function f(id, parameters, callback) { console.log(typeof(parameters)+""+typeof(callback)); } f("hi", {"a":"boo <p><center>[wp_ad_camp_3]</center></p><hr><P>你能覆盖这个功能吗?这不管用吗?</P>[cc lang="javascript"]function doSomething(id){} function doSomething(id,parameters){} function doSomething(id,parameters,callback){} |