Quelle est la raison d'utiliser null au lieu d'indéfini dans JavaScript?

103

J'écris du JavaScript depuis assez longtemps maintenant, et je n'ai jamais eu de raison de l'utiliser null. Il semble que ce undefinedsoit toujours préférable et sert le même objectif par programme. Quelles sont les raisons pratiques à utiliser à la nullplace de undefined?

Jimmy Cuadra
la source
Ceci est un doublon possible de stackoverflow.com/questions/461966/…
Lawnsea
Eh bien, il existe des méthodes comme document.getElementById()celle-là qui peuvent renvoyer nullmais pas undefined, alors dans ces cas, pourquoi testeriez-vous le retour undefined? (Bien sûr, cela fonctionnerait si vous utilisez ==plutôt que ===, mais quand même, pourquoi
testeriez-
Il peut être utile d'avoir des types prévisibles et cela peut guider la réflexion sur l'utilisation de l'un ou l'autre. Lorsqu'un objet est toujours renvoyé, nécessaire ou voulu par la conception, utilisez null pour des résultats erronés (par exemple document.getElementById('does-not-exist')). Les variables var a;et les fonctions retournent les valeurs par défaut non définies. Dans le passé, null était dans la portée globale, donc son utilisation ralentissait l'exécution et m'avait conduit à préférer d'autres types faussés (false, '', 0) aux références libres. Personnellement, j'évite null à moins qu'il n'y ait une raison impérieuse autrement parce que je le perçois comme étant plus simple, ce qui est généralement mieux.
jimmont

Réponses:

59

Null et undefined sont essentiellement deux valeurs différentes qui signifient la même chose. La seule différence réside dans les conventions d'utilisation de ces derniers dans votre système. Comme certains l'ont mentionné, certaines personnes utilisent null pour signifier "aucun objet" où vous pouvez parfois obtenir un objet alors que non défini signifie qu'aucun objet n'était attendu (ou qu'il y avait une erreur). Mon problème avec cela est qu'il est complètement arbitraire et totalement inutile.

Cela dit, il y a une différence majeure: les variables qui ne sont pas initialisées (y compris les paramètres de fonction où aucun argument n'a été passé, entre autres) sont toujours indéfinies.

C'est pourquoi dans mon code je n'utilise jamais null à moins que quelque chose que je ne contrôle pas retourne null (correspondance regex par exemple). La beauté de ceci est que cela simule beaucoup les choses. Je n'ai jamais à vérifier si x === undefined || x === nul. Et si vous avez l'habitude d'utiliser == ou simplement des trucs comme if (x) .... Arrête ça. !xévaluera à vrai pour une chaîne vide, 0, null, NaN - c'est-à-dire des choses que vous ne voulez probablement pas. Si vous voulez écrire du javascript qui n'est pas terrible, utilisez toujours triple equals === et n'utilisez jamais null (utilisez plutôt undefined). Cela vous facilitera la vie.

BT
la source
137
Je ne suis pas d'accord avec cela. Null est utilisé pour définir quelque chose de vide par programmation. Undefined signifie que la référence n'existe pas. Une valeur nulle a une référence définie à «rien». Si vous appelez une propriété non existante d'un objet, vous obtiendrez undefined. Si je devais rendre cette propriété intentionnellement vide, alors elle doit être nulle pour que vous sachiez que c'est exprès. De nombreuses bibliothèques javascript fonctionnent de cette manière.
com2ghz
6
@ com2ghz Ce que vous décrivez est l'une des nombreuses philosophies. De nombreuses bibliothèques js fonctionnent en effet de cette façon. Beaucoup ne fonctionnent pas de cette façon. En javascript, vous pouvez aussi facilement stocker une valeur non définie explicite dans un objet ou un tableau que vous le pouvez avec null. Les significations des deux dépendent complètement et entièrement du contexte. IE ils veulent dire ce que vous voulez qu'ils signifient.
BT
3
C'est pourquoi JS est un langage horrible. Comme vous le dites, de nombreuses bibliothèques ont leurs propres philosophies, mais vous incluez de nombreuses bibliothèques pour un projet. Vous rencontrez donc de nombreuses conventions de ces bibliothèques. Combien de fois devez-vous effectuer différentes vérifications erronées. Ce ne serait pas la dernière fois que vous concatériez un objet nul en une chaîne et que vous obtiendrez un "nul" sous forme de chaîne. Ou en passant un 0 comme valeur numérique et en se demandant pourquoi l'instruction IF gère t comme un faux.
com2ghz
2
@ com2ghz Donc JS est un langage horrible parce qu'il est à la fois nul et indéfini? Je peux compter des dizaines de mauvaises décisions linguistiques dans toutes les langues principales, js n'y fait aucune exception. Je n'ai littéralement jamais besoin ou ne veux utiliser de fausses vérifications dans mon code et j'utilise toujours ===ou !==. JS est un langage incroyablement expressif si vous savez comment vous en servir.
BT
6
Droite. Je viens d'apprendre que la dichotomie null/ undefinedétait nécessaire car la version initiale de JS n'avait hasOwnPropertyni l' inopérateur. Maintenant que c'est le cas, je ne comprends pas vraiment pourquoi l'un d'entre eux n'a pas été aboli dans ES6 ou dans les propositions ES7 que j'ai vues.
Andy
86

Je n'ai pas vraiment de réponse, mais selon Nicholas C. Zakas , page 30 de son livre " Professional JavaScript for Web Developers " :

Lors de la définition d'une variable destinée à contenir ultérieurement un objet, il est conseillé d'initialiser la variable nullpar opposition à autre chose. De cette façon, vous pouvez vérifier explicitement la valeur nullpour déterminer si la variable a été remplie avec une référence d'objet ultérieurement

bbg
la source
8
+1 oui, je suis d'accord et j'essaie toujours de me rappeler d'initialiser vars à null. Ensuite, je suis (assez) sûr que cela undefinedsignifie qu'une catastrophe s'est produite. Juste à mon humble avis.
Pete Wilson
9
@Pete - mais cela ne vous dit rien sur le "désastre", alors à quoi ça sert? Et vous ne pouvez faire cette hypothèse que si vous savez que la fonction suit la convention.
RobG
7
D'autre part, vous pouvez également initialiser la variable avec var myVar;et vérifier explicitement la valeur undefinedpour déterminer si elle a été remplie ultérieurement avec une référence d'objet. Mon point est que c'est totalement théorique - vous pouvez le faire dans les deux sens, et quiconque conseille dans un sens plutôt que dans l'autre ne fait que pousser sa propre convention.
thdoan
1
Le seul problème que j'ai (depuis que j'ai commencé avec JavaScript il y a 15 ans) est que vous devez trop souvent tester undefinedet null. C'est toujours vraiment ennuyeux. J'évite d'assigner une variable à nulljuste pour réduire le nombre de nulltests supplémentaires .
G Man
4
@GMan - C'est le seul endroit où la ==comparaison (par opposition à ===) a du sens: v == null(ou v == undefined) vérifiera la valeur nulle ou non définie.
Rick Love
14

À la fin de la journée, parce que les deux nullet undefinedcontraignent à la même valeur ( Boolean(undefined) === false && Boolean(null) === false), vous pouvez techniquement utiliser l'un ou l'autre pour faire le travail. Cependant, il y a la bonne manière, l'OMI.

  1. Laissez l'utilisation de undefinedau compilateur JavaScript.

    undefinedest utilisé pour décrire des variables qui ne pointent pas vers une référence. C'est quelque chose que le compilateur JS prendra soin de vous. Au moment de la compilation, le moteur JS définira la valeur de toutes les variables levées sur undefined. Au fur et à mesure que le moteur parcourt le code et que les valeurs deviennent disponibles, le moteur attribue des valeurs respectives aux variables respectives. Pour les variables pour lesquelles il n'a pas trouvé de valeurs, les variables continueraient à maintenir une référence à la primitive undefined.

  2. N'utilisez NULL que si vous souhaitez explicitement désigner la valeur d'une variable comme n'ayant "aucune valeur".

    Comme l'indique @ com2gz: nullest utilisé pour définir quelque chose de vide par programmation. undefinedveut dire que la référence n'existe pas. Une nullvaleur a une référence définie à «rien». Si vous appelez une propriété non existante d'un objet, vous obtiendrez undefined. Si je veux rendre cette propriété intentionnellement vide, alors ce doit être nullpour que vous sachiez que c'est exprès.

TLDR; N'utilisez pas le undefinedprimitif. C'est une valeur que le compilateur JS définira automatiquement pour vous lorsque vous déclarez des variables sans affectation ou si vous essayez d'accéder aux propriétés d'objets pour lesquels il n'y a pas de référence. D'autre part, utilisez nullsi et seulement si vous voulez intentionnellement qu'une variable n'ait «aucune valeur».

Je n'ai jamais défini explicitement quoi que ce soit sur undefined (et je n'ai pas rencontré cela dans les nombreuses bases de code avec lesquelles j'ai interagi). De plus, j'utilise rarement null. Les seules fois que j'utilise, nullc'est lorsque je veux désigner la valeur d'un argument d'une fonction comme n'ayant aucune valeur, c'est-à-dire:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello
Govind Rai
la source
Cela aurait dû être la réponse choisie
alaboudi
13

indéfini, c'est là où aucune notion de la chose n'existe; il n'a pas de type, et il n'a jamais été référencé auparavant dans cette portée; null est l'endroit où la chose est connue pour exister, mais elle n'a aucune valeur.

Yaplex
la source
4
Comment savoir si une tentative a été faite pour attribuer une valeur, mais si elle a échoué et si undefined a été attribué à la place?
RobG
11

Chacun a sa propre façon de coder et sa propre sémantique interne, mais au fil des ans, j'ai trouvé que c'était le conseil le plus intuitif que je donne aux gens qui se posent cette question: en cas de doute, faites ce que fait JavaScript .

Disons que vous travaillez avec des propriétés d'objet comme des options pour un plugin jQuery ... demandez-vous quelle valeur JavaScript donne une propriété qui n'a pas encore été définie - la réponse est undefined. Donc, dans ce contexte, je initialiserais ces types de choses avec 'undefined' pour être cohérent avec JavaScript (pour les variables, vous pouvez le faire à la var myVar;place de var myVar = undefined;).

Maintenant, disons que vous faites une manipulation DOM ... quelle valeur JavaScript attribue-t-il aux éléments inexistants? La réponse est null. C'est la valeur avec laquelle je initialiserais si vous créez une variable d'espace réservé qui contiendra plus tard une référence à un élément, un fragment de document ou similaire lié au DOM.

Si vous travaillez avec JSON, un cas particulier doit être fait: pour les valeurs de propriété non définies, vous devez les définir sur ""ou nullparce qu'une valeur de undefinedn'est pas considérée comme le format JSON approprié.

Cela dit, comme une affiche précédente l'a exprimé, si vous constatez que vous initialisez des éléments avec nullou undefinedplus d'une fois dans une lune bleue, vous devriez peut-être reconsidérer la façon dont vous codez votre application.

thdoan
la source
Bien que ce soit une bonne position, j'aimerais ajouter cette réponse: stackoverflow.com/a/37980662/883303
Frederik Krautwald
@FrederikKrautwald merci pour le lien - c'est une délimitation très claire.
thdoan
10

Vous pourriez adopter la convention suggérée ici, mais il n'y a vraiment aucune bonne raison de le faire. Il n'est pas utilisé de manière suffisamment cohérente pour être significatif.

Pour rendre la convention utile, vous devez d'abord savoir que la fonction appelée suit la convention. Ensuite, vous devez tester explicitement la valeur renvoyée et décider quoi faire. Si vous êtes indéfini , vous pouvez supposer qu'une erreur s'est produite et que la fonction appelée était au courant . Mais si une erreur s'est produite et que la fonction le savait, et qu'il est utile de l'envoyer dans un environnement plus large, pourquoi ne pas utiliser un objet d'erreur? c'est-à-dire jeter une erreur?

Donc en fin de compte, la convention est pratiquement inutile dans autre chose que de très petits programmes dans des environnements simples.

RobG
la source
3

Une propriété utile dans null qui n'est pas définie ne qualifie pas:

> null + 3
3
> undefined + 3
NaN

J'utilise nullquand je veux «désactiver» une valeur numérique, ou en initialiser. Ma dernière utilisation était de manipuler la transformation css:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

Je ne sais pas si je devrais utiliser cette propriété pensée ...

Faccion
la source
2

Les nœuds et éléments DOM ne sont pas indéfinis, mais peuvent être nuls.

  • Le nextSibling du dernier enfant d'un élément est nul.

  • Le previousSibling du premier enfant est nul.

  • Une référence document.getElementById est nulle si l'élément n'existe pas dans le document.

Mais dans aucun de ces cas, la valeur n'est indéfinie ; il n'y a tout simplement pas de nœud là-bas.

Kennebec
la source
Merci pour l'explication. Pour moi, cela ne pourrait pas être plus contre-intuitif.
tomekwi
Cela dépend vraiment de ce que vous essayez de vérifier. Par exemple, si vous voulez voir si une variable globale nommée «myVar» existe, alors window.myVarrenvoie «undefined si elle n'existe pas. Il y a des tonnes de choses qui retournent «indéfini» en JavaScript, juste il y a des tonnes de choses qui renvoient «null» - tout dépend du contexte.
thdoan
2

Quelques-uns ont dit qu'il était possible d'initialiser des objets avec null. Je voulais juste souligner que les valeurs par défaut des arguments de déstructuration ne fonctionnent pas null. Par exemple:

const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

Cela nécessite d'effectuer des nullvérifications avant d'appeler la fonction, ce qui peut arriver souvent.

Matt Way
la source
1

Je travaille sur cette question exacte en ce moment et j'examine la philosophie suivante:

  1. Toute fonction destinée à renvoyer un résultat doit retourner null si elle ne parvient pas à trouver un résultat
  2. Toute fonction qui n'est PAS destinée à renvoyer un résultat renvoie implicitement undefined.

Pour moi, cette question est importante parce que quiconque appelle une fonction qui renvoie un résultat ne devrait avoir aucune question quant à savoir s'il faut tester undefined vs null.

Cette réponse ne tente pas de traiter:

  1. Valeurs de propriété nulles ou non définies
  2. Les variables au sein de vos fonctions sont nulles et non définies

À mon avis, les variables sont votre propre entreprise et ne font pas partie de votre API, et les propriétés de tout système OO sont définies et doivent donc être définies avec une valeur différente de ce qu'elles seraient si elles n'étaient pas définies (nul pour défini, indéfini est ce que vous get lors de l'accès à quelque chose qui n'est pas dans votre objet).

Michael
la source
1

Voici une raison: var undefined = 1 c'est du javascript légal, mais var null = 1c'est une erreur de syntaxe. La différence est qu'il nulls'agit d'un mot-clé de langue, alors que ce undefinedn'est pas le cas pour une raison quelconque.

Si votre code repose sur des comparaisons undefinedcomme s'il s'agissait d'un mot-clé ( if (foo == undefined)- une erreur très facile à faire) qui ne fonctionne que parce que personne n'a défini une variable avec ce nom. Tout ce code est vulnérable à la définition accidentelle ou malveillante d'une variable globale portant ce nom. Bien sûr, nous savons tous que définir accidentellement une variable globale est totalement impossible en javascript ...

Joel Mueller
la source
1
Utilisez void 0au lieu de non défini.
Frederik Krautwald
1

Je veux juste ajouter qu'avec l'utilisation de certaines bibliothèques javascript, null et undefined peuvent avoir des conséquences inattendues.

Par exemple, la getfonction de lodash , qui accepte une valeur par défaut comme troisième argument:

const user = {
  address: {
    block: null,
    unit: undefined,
  }
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

Autre exemple: si vous utilisez defaultProps dans React, si une propriété est transmise null, les accessoires par défaut ne sont pas utilisés car null est interprété comme une valeur définie . par exemple

class MyComponent extends React.Component {
   static defaultProps = {
      callback: () => {console.log('COMPONENT MOUNTED')},
   }
   componentDidMount() {
      this.props.callback();
   }
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"
lilbitofchee
la source
0

Je ne suis absolument pas d'accord pour dire que l'utilisation nulle ou non définie n'est pas nécessaire. undefined est une chose qui maintient en vie tout le processus de chaînage de prototype. Ainsi, le compilateur uniquement avec null ne peut pas vérifier si cette propriété est juste égale à null ou n'est pas définie dans le prototype de point de terminaison. Dans d'autres langages typés dynamiques (par exemple Python), il lève une exception si vous voulez accéder à une propriété non définie, mais pour les langages basés sur des prototypes, le compilateur doit également vérifier les prototypes parents et voici l'endroit où le besoin indéfini est le plus important.

Toute la signification de l'utilisation de null est simplement de lier une variable ou une propriété avec un objet qui est singleton et qui a une signification de vide, et l'utilisation de null a également des objectifs de performance. Ce code 2 a un temps d'exécution différent.

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p1();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p2();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p; 
});
big_array.reduce((sum, p)=> sum + p.value, 0)
VahagnNikoghosian
la source
0

Variable inconnue: undefined.

Variable connue encore aucune valeur: null.

  1. Vous recevez un objet à partir d' un serveur, server_object.
  2. Vous faites référence server_object.errj. Cela vous dit que c'est undefined. Cela signifie qu'il ne sait pas ce que c'est.
  3. Maintenant, vous faites référence server_object.err. Cela vous dit que c'est null. Cela signifie que vous faites référence à une variable correcte mais qu'elle est vide; donc pas d'erreur.

Le problème est lorsque vous déclarez un nom de variable sans valeur ( var hello) js déclare que undefined: cette variable n'existe pas; alors que les programmeurs veulent surtout dire: «Je ne lui ai pas encore donné de valeur», la définition de null.

Ainsi, le comportement par défaut d'un programmeur - déclarer une variable sans valeur comme rien - est en contradiction avec js - en la déclarant comme non existante. Et d'ailleurs, !undefinedet !nullsont les deuxtrue donc la plupart des programmeurs les traitent comme équivalents.

Vous pouvez bien sûr vous assurer que vous le faites toujours, var hello = nullmais la plupart ne jetteront pas leur code en tant que tel pour garantir la cohérence du type dans un langage délibérément mal typé, quand eux et l' !opérateur traitent les deux undefinedet nullcomme équivalents.

newfivefour
la source