Mam statyczną funkcję javascript, która może przyjmować 1, 2 lub 3 parametry:
function getData(id, parameters, callback) //parameters (associative array) and callback (function) are optional
Wiem, że zawsze mogę sprawdzić, czy dany parametr jest niezdefiniowany, ale skąd mam wiedzieć, czy przekazano parametr, czy wywołanie zwrotne?
Jaki jest najlepszy sposób na zrobienie tego?
Przykłady tego, co można przekazać:
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);
javascript
jd.
źródło
źródło
Odpowiedzi:
Możesz wiedzieć, ile argumentów zostało przekazanych do twojej funkcji i możesz sprawdzić, czy twój drugi argument jest funkcją, czy nie:
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; } } //... }
Możesz również użyć obiektu arguments w następujący sposób:
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]; } //... }
Jeśli jesteś zainteresowany, zajrzyj do tego artykułu autorstwa Johna Resiga, na temat techniki symulacji przeciążania metod w JavaScript.
źródło
Eee - to by oznaczało, że wywołujesz swoją funkcję z argumentami, które nie są w odpowiedniej kolejności ... czego nie polecałbym.
Zalecałbym zamiast tego podawanie obiektu do twojej funkcji w następujący sposób:
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'); } } );
Korzyści:
Wady:
Jeśli nie masz wyboru, możesz użyć funkcji do wykrycia, czy obiekt jest rzeczywiście funkcją (zobacz ostatni przykład).
Uwaga: to jest właściwy sposób wykrywania funkcji:
function isFunction(obj) { return Object.prototype.toString.call(obj) === "[object Function]"; } isFunction( function(){} )
źródło
Dlatego użyj operatora typeof, aby określić, czy drugi parametr jest tablicą czy funkcją.
Może to dać kilka sugestii: http://www.planetpdf.com/developer/article.asp?ContentID=testing_for_object_types_in_ja
Nie jestem pewien, czy to praca, czy praca domowa, więc nie chcę w tej chwili udzielać odpowiedzi, ale typ pomoże ci to określić.
źródło
Należy sprawdzić rodzaj otrzymywanych parametrów. Może powinieneś użyć
arguments
tablicy, ponieważ drugi parametr może czasami być „parametrami”, a czasami „wywołaniem zwrotnym” i nazwanie go parametrami może być mylące.źródło
Wiem, że to dość stare pytanie, ale ostatnio zajmowałem się tym. Daj mi znać, co myślisz o tym rozwiązaniu.
Stworzyłem narzędzie, które pozwala mi silnie wpisywać argumenty i pozostawić je opcjonalne. Zasadniczo zawijasz swoją funkcję w proxy. Jeśli pominiesz argument, jest on niezdefiniowany . Może się to wydawać dziwne, jeśli masz wiele opcjonalnych argumentów tego samego typu obok siebie. (Istnieją opcje przekazywania funkcji zamiast typów do wykonywania niestandardowych sprawdzeń argumentów, a także określanie wartości domyślnych dla każdego parametru).
Tak wygląda implementacja:
function displayOverlay(/*message, timeout, callback*/) { return arrangeArgs(arguments, String, Number, Function, function(message, timeout, callback) { /* ... your code ... */ }); };
Dla jasności, oto co się dzieje:
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 ... */ } ); };
Możesz wyświetlić kod proxyrangeArgs w moim repozytorium GitHub tutaj:
https://github.com/joelvh/Sysmo.js/blob/master/sysmo.js
Oto funkcja narzędzia z kilkoma komentarzami skopiowanymi z repozytorium:
/* ****** 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(); }
źródło
Polecam użycie ArgueJS .
Możesz po prostu wpisać swoją funkcję w ten sposób:
function getData(){ arguments = __({id: String, parameters: [Object], callback: [Function]}) // and now access your arguments by arguments.id, // arguments.parameters and arguments.callback }
Rozważyłem na podstawie twoich przykładów, że chcesz, aby twój
id
parametr był ciągiem, prawda? TerazgetData
wymagaString id
i akceptuje opcjeObject parameters
iFunction callback
. Wszystkie opublikowane przypadki użycia będą działać zgodnie z oczekiwaniami.źródło
Możesz użyć właściwości obiektu arguments wewnątrz funkcji.
źródło
Mówisz, że możesz mieć takie wywołania: getData (id, parameters); getData (id, callback)?
W tym przypadku nie możesz oczywiście polegać na pozycji i musisz polegać na analizie typu: getType (), a następnie, jeśli to konieczne, getTypeName ()
Sprawdź, czy dany parametr jest tablicą czy funkcją.
źródło
Myślę, że chcesz tutaj użyć 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"
źródło
Jeśli twój problem dotyczy tylko przeciążenia funkcji (musisz sprawdzić, czy parametr 'parameters' to 'parametry', a nie 'callback'), radziłbym nie przejmować się typem argumentu i
użyć tego podejścia . Pomysł jest prosty - użyj obiektów dosłownych, aby połączyć parametry:
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!");} });
źródło
Myślę, że to może być zrozumiały przykład:
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); }
źródło
Czy możesz zastąpić tę funkcję? Czy to nie zadziała:
function doSomething(id){} function doSomething(id,parameters){} function doSomething(id,parameters,callback){}
źródło