web-dev-qa-db-fra.com

La transmission de NULL en tant que paramètre dans ES6 n'utilise pas le paramètre par défaut lorsqu'il est fourni

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!
45
aus_lacy

Ce n'est pas si évident

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é.

Exemples contraires

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:

  1. passer undefined est différent que ne pas passer du tout un argument
  2. parfois null peut être une valeur par défaut au lieu de undefined

Décision TC39

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.

Autres langues

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).

Ce que tu peux faire

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...

Conclusion

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.

23
rsp

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.

29
doldt

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.

1
taxicala