J'ai maintenant vu 2 méthodes pour déterminer si un argument a été passé à une fonction JavaScript. Je me demande si une méthode est meilleure que l'autre ou si l'une d'entre elles est mauvaise à utiliser?
function Test(argument1, argument2) {
if (Test.arguments.length == 1) argument2 = 'blah';
alert(argument2);
}
Test('test');
Ou
function Test(argument1, argument2) {
argument2 = argument2 || 'blah';
alert(argument2);
}
Test('test');
Autant que je sache, ils aboutissent tous deux à la même chose, mais je n’avais utilisé que le premier en production.
Une autre option mentionnée par Tom :
function Test(argument1, argument2) {
if(argument2 === null) {
argument2 = 'blah';
}
alert(argument2);
}
Selon le commentaire de Juan, il serait préférable de modifier la suggestion de Tom en:
function Test(argument1, argument2) {
if(argument2 === undefined) {
argument2 = 'blah';
}
alert(argument2);
}
Il existe différentes manières de vérifier si un argument a été passé à une fonction. En plus des deux que vous avez mentionnés dans votre question (originale) - vérifier arguments.length
ou utiliser l'opérateur ||
pour fournir des valeurs par défaut - vous pouvez également vérifier explicitement les arguments de undefined
via argument2 === undefined
ou typeof argument2 === 'undefined'
s'il est paranoïaque (voir commentaires).
L'utilisation de l'opérateur ||
est devenue une pratique courante - tous les enfants cools le font - mais soyez prudent: la valeur par défaut sera déclenchée si l'argument a pour valeur false
, ce qui signifie qu'il pourrait en réalité être undefined
, null
, false
, 0
, ''
(ou tout autre élément pour lequel Boolean(...)
renvoie false
).
La question est donc de savoir quand utiliser quelle vérification, car elles donnent toutes des résultats légèrement différents.
Vérifier arguments.length
présente le comportement "le plus correct", mais cela pourrait ne pas être possible s'il existe plusieurs arguments facultatifs.
Le test pour undefined
est ensuite 'meilleur' - il échoue uniquement si la fonction est explicitement appelée avec une valeur undefined
qui, selon toute vraisemblance, devrait être traitée de la même manière que l'omission de l'argument.
L'utilisation de l'opérateur ||
peut déclencher l'utilisation de la valeur par défaut même si un argument valide est fourni. D'un autre côté, son comportement pourrait être réellement souhaité.
Pour résumer: tilisez-le uniquement si vous savez ce que vous faites!
À mon avis, utiliser ||
est également la méthode à utiliser s’il existe plusieurs arguments facultatifs et qu’un ne veut pas passer un littéral d’objet comme solution de contournement pour les paramètres nommés.
Un autre moyen intéressant de fournir des valeurs par défaut à l'aide de arguments.length
est possible en passant par les étiquettes d'une instruction switch:
function test(requiredArg, optionalArg1, optionalArg2, optionalArg3) {
switch(arguments.length) {
case 1: optionalArg1 = 'default1';
case 2: optionalArg2 = 'default2';
case 3: optionalArg3 = 'default3';
case 4: break;
default: throw new Error('illegal argument count')
}
// do stuff
}
Cela a l'inconvénient que l'intention du programmeur n'est pas (visuellement) évidente et utilise des "nombres magiques"; il est donc peut-être sujet aux erreurs.
Si vous utilisez jQuery, une option intéressante (en particulier pour les situations compliquées) consiste à utiliser méthode extend de jQuery .
function foo(options) {
default_options = {
timeout : 1000,
callback : function(){},
some_number : 50,
some_text : "hello world"
};
options = $.extend({}, default_options, options);
}
Si vous appelez la fonction alors comme ceci:
foo({timeout : 500});
La variable options serait alors:
{
timeout : 500,
callback : function(){},
some_number : 50,
some_text : "hello world"
};
C'est l'un des rares cas où je trouve le test:
if(! argument2) {
}
fonctionne assez bien et porte l’implication correcte syntaxiquement.
(Avec la restriction simultanée que je ne permettrais pas une valeur nulle légitime pour argument2
qui a une autre signification; mais ce serait vraiment déroutant.)
MODIFIER:
C’est un très bon exemple de différence stylistique entre les langages faiblement typés et les langages fortement typés; et une option stylistique que javascript offre à la volée.
Ma préférence personnelle (sans faire de critique pour d’autres préférences) est le minimalisme. Moins le code doit en dire, tant que je suis cohérent et concis, moins une autre personne doit comprendre pour inférer correctement mon sens.
Une implication de cette préférence est que je ne veux pas - je ne trouve pas cela utile - empiler un tas de tests de dépendance de type. Au lieu de cela, j'essaie de faire en sorte que le code ait une signification réelle. et ne testez que ce que je vais vraiment devoir tester.
L'une des aggravations que je constate dans le code de certains autres peuples consiste à déterminer si, dans le contexte plus large, ils s'attendent ou non à se retrouver dans les cas pour lesquels ils effectuent des tests. Ou s’ils essaient de tester tout ce qui est possible, ils risquent de ne pas anticiper suffisamment le contexte. Ce qui signifie que je finis par avoir besoin de les retrouver de manière exhaustive dans les deux sens avant de pouvoir refacturer ou modifier quoi que ce soit en toute confiance. Je suppose qu'il est fort probable qu'ils aient mis en place ces différents tests car ils prévoyaient des circonstances dans lesquelles ils seraient nécessaires (et qui ne me sont généralement pas évidents).
(Je considère que ces personnes utilisent un langage dynamique comme inconvénient majeur. Trop souvent, les utilisateurs ne veulent pas abandonner tous les tests statiques et finissent par les imiter.)
C'est ce que j'ai constaté de la manière la plus flagrante lors de la comparaison d'un code ActionScript 3 complet avec un code JavaScript élégant. L'AS3 peut représenter 3 à 4 fois le volume des js, et la fiabilité que je soupçonne n'est pas meilleure, uniquement en raison du nombre (3-4X) de décisions de codage prises.
Comme tu le dis, Shog9, YMMV. :RÉ
Il y a des différences significatives. Configurons quelques cas de test:
var unused; // value will be undefined
Test("test1", "some value");
Test("test2");
Test("test3", unused);
Test("test4", null);
Test("test5", 0);
Test("test6", "");
Avec la première méthode que vous décrivez, seul le deuxième test utilisera la valeur par défaut. La seconde méthode utilisera toutes les options sauf la première (car JS convertira undefined
, null
, 0
et ""
en le booléen false
. Et si vous devaient utiliser la méthode de Tom, seul le quatrième test utilisera la méthode par défaut!
La méthode que vous choisissez dépend vraiment de votre comportement souhaité. Si des valeurs autres que undefined
sont autorisées pour argument2
, vous souhaiterez probablement une certaine variation sur le premier; si une valeur non nulle, non nulle et non vide est souhaitée, la seconde méthode est idéale - en fait, elle est souvent utilisée pour éliminer rapidement une plage de valeurs aussi étendue.
url = url === undefined ? location.href : url;
Dans ES6 (ES2015), vous pouvez utiliser paramètres par défaut
function Test(arg1 = 'Hello', arg2 = 'World!'){
alert(arg1 + ' ' +arg2);
}
Test('Hello', 'World!'); // Hello World!
Test('Hello'); // Hello World!
Test(); // Hello World!
Je suis désolé, je ne peux toujours pas commenter, alors pour répondre à la réponse de Tom ... En javascript (undefined! = Null) == false En fait, cette fonction ne fonctionnera pas avec "null", vous devrez utiliser "undefined"
Pourquoi ne pas utiliser l'opérateur !!
? Cet opérateur, placé avant la variable, le transforme en un booléen (si j'ai bien compris), donc !!undefined
et !!null
(et même !!NaN
, ce qui peut être très intéressant) retourne false
.
Voici un exemple:
function foo(bar){
console.log(!!bar);
}
foo("hey") //=> will log true
foo() //=> will log false
Il y a un moyen aussi difficile de trouver si un paramètre est passé à une fonction ou non . Regardez l'exemple ci-dessous:
this.setCurrent = function(value) {
this.current = value || 0;
};
Cela signifie que si la valeur de value
n’est pas présente/transmise, définissez-la sur 0.
Assez cool hein!
Il peut être pratique d’approcher la détection des arguments en évoquant votre fonction avec un objet de propriétés facultatives:
function foo(options) {
var config = { // defaults
list: 'string value',
of: [a, b, c],
optional: {x: y},
objects: function(param){
// do stuff here
}
};
if(options !== undefined){
for (i in config) {
if (config.hasOwnProperty(i)){
if (options[i] !== undefined) { config[i] = options[i]; }
}
}
}
}
Parfois, vous pouvez également vérifier le type, surtout si vous utilisez la fonction comme getter et setter. Le code suivant est ES6 (ne fonctionnera pas dans EcmaScript 5 ou plus ancien):
class PrivateTest {
constructor(aNumber) {
let _aNumber = aNumber;
//Privileged setter/getter with access to private _number:
this.aNumber = function(value) {
if (value !== undefined && (typeof value === typeof _aNumber)) {
_aNumber = value;
}
else {
return _aNumber;
}
}
}
}