Y a-t-il une raison connue pour laquelle le fait de passer null
comme paramètre dans ES6 n'utilise pas le paramètre par défaut lorsqu'il est fourni?
function sayHello(name = "World") {
console.log("Hello, " + name + "!");
}
sayHello("Jim"); // Hello, Jim!
sayHello(undefined); // Hello, World!
sayHello(null); // Hello, null!
J'ai lu quelques commentaires expliquant pourquoi undefined
est complètement différent de null
et c'est pourquoi il explique le comportement actuel des paramètres par défaut.
On pourrait faire valoir que le passage explicite non défini ne devrait pas déclencher la substitution de valeur par défaut parce que lorsque j'ai une fonction:
const f = (x = 'default') => console.log(x);
Je voudrais qu'il imprime "default"
Lorsque je l'exécute en tant que:
f();
mais je voudrais qu'il imprime "undefined"
quand je l'exécute explicitement comme:
f(undefined);
car sinon pourquoi devrais-je utiliser f(undefined)
en premier lieu? Il est clair que mon intention ici est de fournir un argument au lieu de le laisser de côté.
Maintenant, considérez cette fonction:
const g = (...a) => console.log(JSON.stringify(a));
Quand je l'utilise comme:
g();
J'obtiens: []
Mais quand je l'utilise comme:
g(undefined);
J'obtiens: [null]
ce qui démontre clairement que:
undefined
est différent que ne pas passer du tout un argumentnull
peut être une valeur par défaut au lieu de undefined
Un aperçu du comportement actuel des paramètres par défaut peut être consulté dans les notes de réunion du 24 juillet 2012 par TC39:
Soit dit en passant, cela montre que le passage explicite de undefined
à l'origine n'a pas déclenché la valeur par défaut dans le premier brouillon et il y a eu une discussion pour savoir si ou non, il devrait le faire. Donc, comme vous pouvez le voir, le comportement actuel n'était pas aussi évident pour les membres du TC39 qu'il le semble maintenant pour les personnes qui commentent ici.
Cela étant dit, la décision de ce qui devrait et de ce qui ne devrait pas déclencher la substitution de valeur par défaut est complètement arbitraire à la fin de la journée. Même avoir un undefined
et null
séparé peut être assez étrange si vous y pensez. Certains langages n'ont que undefined
(comme undef
en Perl), certains n'ont que null
(comme Java), certains langages utilisent des équivalents de false
ou un vide liste ou tableau pour cela (comme Scheme où vous pouvez avoir une liste vide ou #f
(false) mais il n'y a pas d'équivalent de null
qui serait distinct à la fois d'une liste vide et d'une fausse valeur ) et certains langages n'ont même pas d'équivalents null
, false
ou undefined
(comme C qui utilise des entiers au lieu de true
et false
et un pointeur NULL qui est en fait un pointeur normal pointant vers l'adresse 0 - rendant cette adresse inaccessible même lorsqu'elle est mappée par un code qui teste les pointeurs nuls).
Maintenant, je peux comprendre votre besoin de remplacer les valeurs par défaut par null
. Malheureusement, ce n'est pas un comportement par défaut mais vous pouvez créer une fonction simple pour vous aider:
const N = f => (...a) => f(...a.map(v => (v === null ? undefined : v)));
Maintenant, chaque fois que vous voulez que les valeurs par défaut soient substituées aux valeurs null
, vous pouvez l'utiliser comme ceci. Par exemple. si vous avez cette fonction dans l'un des exemples ci-dessus:
const f = (x = 'default') => console.log(x);
il affichera "default"
pour f()
et f(undefined)
mais pas pour f(null)
. Mais lorsque vous utilisez la fonction N
définie ci-dessus pour définir la fonction f
comme ceci:
const f = N((x = 'default') => console.log(x));
maintenant f()
et f(undefined)
mais aussi f(null)
imprime "default"
.
Si vous souhaitez un comportement quelque peu différent, par ex. en substituant les valeurs par défaut aux chaînes vides - utile pour les variables d'environnement qui peuvent parfois être définies sur des chaînes vides au lieu de ne pas exister, vous pouvez utiliser:
const N = f => (...a) => f(...a.map(v => (v === '' ? undefined : v)));
Si vous voulez que toutes les valeurs de falsification soient substituées, vous pouvez l'utiliser comme ceci:
const N = f => (...a) => f(...a.map(v => (v || undefined)));
Si vous souhaitez remplacer des objets vides, vous pouvez utiliser:
const N = f => (...a) => f(...a.map(v => (Object.keys(v).length ? v : undefined)));
etc...
Le fait est que c'est votre code et que vous savez quelle devrait être l'API de vos fonctions et comment les valeurs par défaut devraient fonctionner. Heureusement, JavaScript est assez puissant pour vous permettre d'atteindre facilement ce dont vous avez besoin (même si ce n'est pas le comportement par défaut des valeurs par défaut, pour ainsi dire) avec une magie de fonction d'ordre supérieur.
C'est ainsi que les paramètres par défaut sont définis dans la spécification. Voir MDN : (accent sur le mien)
Les paramètres de fonction par défaut permettent aux paramètres formels d'être initialisés avec des valeurs par défaut si aucune valeur ou indéfinie est transmise.
null
n'est ni aucune valeur, ni undefined
, donc il ne déclenche pas l'initialisation par défaut.
null
est une valeur qui ne déclenchera pas la valeur par défaut à utiliser, les valeurs par défaut seront utilisées lorsque l'argument est undefined
.