La vie étrange de NaN en JavaScript
Vous l’avez déjà rencontré : un calcul renvoie NaN, et soudain l’ensemble de votre pipeline de données produit des résultats incohérents. Ou pire, une comparaison censée détecter le problème échoue silencieusement parce que NaN === NaN renvoie false. Comprendre les particularités de NaN en JavaScript n’est pas optionnel—c’est essentiel pour écrire du code numérique fiable.
Cet article explique pourquoi NaN se comporte de cette manière, où il apparaît couramment, et comment le détecter correctement à l’aide de méthodes modernes.
Points clés à retenir
- NaN est un type number valide selon la norme IEEE 754, représentant des résultats mathématiques indéfinis ou non représentables.
- NaN n’est jamais égal à lui-même—utilisez
Number.isNaN()ouObject.is()pour une détection fiable. - La fonction globale
isNaN()effectue une coercition préalable des arguments, causant des faux positifs ; évitez-la. - La sérialisation JSON convertit silencieusement NaN en
null, tandis questructuredClone()le préserve. - Validez les entrées numériques aux frontières pour empêcher NaN de se propager dans les calculs.
Pourquoi NaN existe et pourquoi typeof renvoie “number”
NaN signifie “Not a Number” (pas un nombre), pourtant typeof NaN renvoie "number". Ce n’est pas un bug JavaScript—c’est voulu.
La norme IEEE 754 pour les nombres à virgule flottante, que JavaScript respecte, définit NaN comme une valeur spéciale au sein du type number. Il représente le résultat d’opérations mathématiques indéfinies ou non représentables. Considérez-le comme un marqueur qui indique “ce calcul n’a pas produit de résultat numérique valide”.
console.log(typeof NaN) // "number"
NaN existe parce que les opérations numériques ont besoin d’un moyen de signaler un échec sans lever d’exceptions. La division par zéro avec des entiers provoquerait un plantage dans de nombreux langages, mais 0 / 0 renvoie NaN et permet à votre programme de continuer.
Sources courantes de NaN en JavaScript
NaN apparaît plus souvent que vous ne le pensez :
// Échec de parsing
Number("hello") // NaN
parseInt("abc") // NaN
// Opérations mathématiques invalides
0 / 0 // NaN
Math.sqrt(-1) // NaN
Infinity - Infinity // NaN
// Opérations avec undefined
undefined * 5 // NaN
Les entrées de formulaires sont un coupable fréquent. Lorsque parseFloat(userInput) rencontre du texte non numérique, NaN entre silencieusement dans vos calculs et se propage à travers chaque opération suivante.
Règles de comparaison de NaN : pourquoi NaN !== NaN
Voici le comportement qui déroute la plupart des développeurs :
NaN === NaN // false
NaN !== NaN // true
La norme IEEE 754 impose cela. Le raisonnement : si deux opérations échouent toutes les deux, vous ne pouvez pas supposer que leurs “échecs” sont équivalents. Math.sqrt(-1) et 0 / 0 produisent tous deux NaN, mais ils représentent des résultats indéfinis différents.
Cela signifie que vous ne pouvez pas utiliser les opérateurs d’égalité pour détecter NaN.
Number.isNaN vs isNaN : la différence critique
JavaScript fournit deux fonctions pour la détection de NaN, mais une seule fonctionne de manière fiable.
La fonction globale isNaN() effectue d’abord une coercition de son argument en nombre :
isNaN("hello") // true (coercition vers NaN, puis vérification)
isNaN(undefined) // true
isNaN({}) // true
Cela produit des faux positifs. La chaîne "hello" n’est pas NaN—c’est une chaîne qui devient NaN lors de la coercition.
Number.isNaN() vérifie sans coercition :
Number.isNaN("hello") // false
Number.isNaN(undefined) // false
Number.isNaN(NaN) // true
Utilisez toujours Number.isNaN() pour une détection précise. Alternativement, Object.is(value, NaN) fonctionne également correctement :
Object.is(NaN, NaN) // true
Discover how at OpenReplay.com.
Comportement de NaN avec JSON : perte de données silencieuse
Lorsque vous sérialisez des données contenant NaN, JSON.stringify() le remplace par null :
JSON.stringify({ value: NaN }) // '{"value":null}'
JSON.stringify([1, NaN, 3]) // '[1,null,3]'
C’est une source courante de bugs lors de l’envoi de données numériques vers des API ou de leur stockage dans des bases de données. Vos valeurs NaN disparaissent silencieusement, et vous recevez null en retour—ce qui peut causer des erreurs différentes en aval.
Validez les données numériques avant la sérialisation si la préservation de NaN est importante.
structuredClone et NaN : préservation dans le clonage moderne
Contrairement à JSON, structuredClone() préserve les valeurs NaN :
const original = { score: NaN }
const cloned = structuredClone(original)
Number.isNaN(cloned.score) // true
Cela rend structuredClone() sûr vis-à-vis de NaN pour la copie profonde d’objets pouvant contenir des résultats numériques invalides. Si vous clonez des structures de données avec des valeurs NaN potentielles, préférez structuredClone() à l’aller-retour JSON.
Propagation de NaN : l’effet viral
Une fois que NaN entre dans un calcul, il contamine chaque résultat :
const result = 5 + NaN // NaN
const final = result * 100 // NaN
Cette propagation est intentionnelle—elle vous empêche d’utiliser accidentellement des données corrompues. Mais cela signifie qu’un seul NaN tôt dans un pipeline peut invalider un ensemble de données entier.
Validez les entrées aux frontières : lors du parsing d’entrées utilisateur, de la réception de réponses API, ou de la lecture depuis des sources externes.
Conclusion
Le comportement étrange de NaN suit des règles logiques une fois que vous comprenez la conception d’IEEE 754. Utilisez Number.isNaN() ou Object.is() pour la détection—jamais les opérateurs d’égalité ou la fonction globale isNaN(). Rappelez-vous que la sérialisation JSON convertit NaN en null, tandis que structuredClone() le préserve. Validez les données numériques aux points d’entrée pour détecter NaN avant qu’il ne se propage dans vos calculs.
FAQ
NaN est défini comme une valeur numérique spéciale par la norme IEEE 754 pour les nombres à virgule flottante, que JavaScript implémente. Il représente le résultat d'opérations mathématiques indéfinies tout en restant dans le système de type number. Cette conception permet aux calculs numériques de continuer sans lever d'exceptions lorsque les opérations échouent.
Non. NaN est la seule valeur JavaScript qui n'est pas égale à elle-même. NaN === NaN et NaN == NaN renvoient tous deux false. Utilisez plutôt Number.isNaN() ou Object.is(value, NaN) pour une détection fiable.
La fonction globale isNaN() effectue une coercition de son argument en nombre avant la vérification, causant des faux positifs pour des valeurs non numériques comme les chaînes ou undefined. Number.isNaN() n'effectue aucune coercition et renvoie true uniquement si la valeur est exactement NaN. Préférez toujours Number.isNaN() pour des résultats précis.
Validez toutes les entrées numériques aux points d'entrée tels que les champs de formulaire, les réponses API et les sources de données externes. Vérifiez les valeurs avec Number.isNaN() immédiatement après le parsing ou la réception des données. Cela empêche NaN de se propager dans les opérations suivantes et d'invalider vos résultats.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.