Gestionarea parametrilor opționali în JavaScript


Am o funcție JavaScript statică care poate primi 1, 2 sau 3 parametri:

function getData(id, parameters, callback) //parameters (associative array) and callback (function) are optional

Știu că pot întotdeauna să verific dacă un anumit parametru este nedefinit, dar cum aș putea ști dacă ceea ce a fost transmis a fost parametrul sau callback-ul?

Care este cea mai bună metodă de a face asta?

Exemple de ceea ce ar putea fi transmis:

Unu

getData('offers');

Doi

var array = new Array();
array['type']='lalal';
getData('offers',array);

Trei

var foo = function (){...}
getData('offers',foo);

Patru

getData('offers',array,foo);

Răspuns #1

Poți să știi câți argumente au fost transmise funcției tale și poți verifica dacă al doilea argument este o funcție sau nu:

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; 
    }
  }
  //...
}

De asemenea, poți folosi obiectul arguments în acest mod:

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];
  }
  //...
}

Dacă ești interesat, aruncă o privire la acest articol de John Resig, despre o tehnică de a simula suprasarcina metodelor în JavaScript.

Răspunsul #2

Ei bine - asta ar implica faptul că invoci funcția ta cu argumente care nu sunt în ordinea corectă... lucru pe care nu l-aș recomanda.

Aș recomanda în schimb să furnizați un obiect funcției dvs. astfel:

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

Beneficii:

  • nu trebuie să ții cont de ordinea argumentelor
  • nu trebuie să faci verificarea tipului
  • este mai ușor să definești valorile implicite deoarece nu este necesară verificarea tipului
  • mai puține dureri de cap. Imaginează-ți dacă ai adăuga un al patrulea argument, ar trebui să îți actualizezi verificarea tipurilor de fiecare dată, și ce se întâmplă dacă al patrulea sau următoarele sunt de asemenea funcții?

Dezavantaje:

  • timp să refactorizăm codul

Dacă nu ai de ales, ai putea folosi o funcție pentru a detecta dacă un obiect este într-adevăr o funcție (vezi ultimul exemplu).

Notă: Aceasta este modalitatea corectă de a detecta o funcție:

function isFunction(obj) {
    return Object.prototype.toString.call(obj) === "[object Function]";
}

isFunction( function(){} )