ES2015 et versions ultérieures
Dans ES2015, la déstructuration des paramètres peut être utilisée pour simuler des paramètres nommés. Il faudrait que l'appelant passe un objet, mais vous pouvez éviter toutes les vérifications à l'intérieur de la fonction si vous utilisez également des paramètres par défaut:
myFunction({ param1 : 70, param2 : 175});
function myFunction({param1, param2}={}){
// ...function body...
}
// Or with defaults,
function myFunc({
name = 'Default user',
age = 'N/A'
}={}) {
// ...function body...
}
ES5
Il existe un moyen de se rapprocher de ce que vous voulez, mais il est basé sur la sortie de Function.prototype.toString
[ES5] , qui dépend dans une certaine mesure de l'implémentation, de sorte qu'il peut ne pas être compatible avec plusieurs navigateurs.
L'idée est d'analyser les noms de paramètres à partir de la représentation sous forme de chaîne de la fonction afin de pouvoir associer les propriétés d'un objet au paramètre correspondant.
Un appel de fonction pourrait alors ressembler à
func(a, b, {someArg: ..., someOtherArg: ...});
où a
etb
sont des arguments positionnels et le dernier argument est un objet avec des arguments nommés.
Par exemple:
var parameterfy = (function() {
var pattern = /function[^(]*\(([^)]*)\)/;
return function(func) {
// fails horribly for parameterless functions ;)
var args = func.toString().match(pattern)[1].split(/,\s*/);
return function() {
var named_params = arguments[arguments.length - 1];
if (typeof named_params === 'object') {
var params = [].slice.call(arguments, 0, -1);
if (params.length < args.length) {
for (var i = params.length, l = args.length; i < l; i++) {
params.push(named_params[args[i]]);
}
return func.apply(this, params);
}
}
return func.apply(null, arguments);
};
};
}());
Que vous utiliseriez comme:
var foo = parameterfy(function(a, b, c) {
console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);
});
foo(1, 2, 3); // a is 1 | b is 2 | c is 3
foo(1, {b:2, c:3}); // a is 1 | b is 2 | c is 3
foo(1, {c:3}); // a is 1 | b is undefined | c is 3
foo({a: 1, c:3}); // a is 1 | b is undefined | c is 3
DEMO
Il y a quelques inconvénients à cette approche (vous avez été prévenu!):
- Si le dernier argument est un objet, il est traité comme un "objet argument nommé"
- Vous obtiendrez toujours autant d'arguments que vous l'avez défini dans la fonction, mais certains d'entre eux peuvent avoir la valeur
undefined
(ce qui est différent de n'avoir aucune valeur). Cela signifie que vous ne pouvez pas utiliser arguments.length
pour tester le nombre d'arguments transmis.
Au lieu d'avoir une fonction créant le wrapper, vous pouvez également avoir une fonction qui accepte une fonction et diverses valeurs comme arguments, telles que
call(func, a, b, {posArg: ... });
ou même étendre Function.prototype
pour que vous puissiez faire:
foo.execute(a, b, {posArg: ...});