53 votes

Rupture sur NaN en JavaScript

Existe-t-il un navigateur moderne qui lève des exceptions lors de la propagation de NaN (c'est-à-dire la multiplication ou l'addition d'un nombre à NaN), ou qui peut être configuré pour le faire ?

La propagation silencieuse des NaN est une source terrible et insidieuse de bogues, et j'aimerais pouvoir les détecter à temps, même si les performances en pâtissent.


Voici un exemple de bug qui use strict , jshint et al. n'ont pas décroché :

object = new MyObject();
object.position.x = 0;
object.position.y = 10;

// ... lots of code

var newPosition = object.position + 1; // <- this is an error, and should
                                       //    have been object.position.x
                                       //    however it fails *silently*,
                                       //    rather than loudly

newPosition *= 2;                      // <- this doesn't raise any errors either.
                                       //    this code is actually ok if the
                                       //    previous line had been correct

Note : Le compilateur TypeScript est capable de détecter des erreurs comme celles ci-dessus, même dans le code JS, si l'inférence de type réussit.

1 votes

Vous pouvez vérifier isNaN() ?

10 votes

Je n'ai pas vraiment envie de truffer mon code de isNaNs à chaque fois que j'ajoute des chiffres.

0 votes

@RUJordan vous pouvez certainement. Mais cela se traduit par BEAUCOUP de code.

38voto

Rob M. Points 5205

Pour répondre à la question posée :

Existe-t-il un navigateur moderne qui lève des exceptions lors de la propagation de NaN (c'est-à-dire la multiplication ou l'addition d'un nombre à NaN), ou qui peut être configuré pour le faire ?

Non. Javascript est un langage très indulgent et ne se préoccupe pas de savoir si vous voulez multiplier le nombre d'utilisateurs. Math.PI par "pomme de terre" (indice : c'est NaN ). C'est juste l'un des mauvais côtés (ou des bons côtés, selon votre point de vue) du langage avec lequel nous, les développeurs, devons composer.

En ce qui concerne le bogue qui vous amène à poser cette question (vraisemblablement), l'utilisation de getters et setters sur vos objets est un moyen solide de faire respecter cette règle et de vous empêcher de faire des erreurs comme celle-ci.

0 votes

J'accepte cette réponse car elle répond le plus directement à la question. Cependant, la réponse de @Jerry résout le cas de l'exécution d'actions numériques à l'aide d'un objet, ce qui répond assez bien à un grand nombre de cas pour le problème réel (sauf pour la multiplication undefined * 3 ou similaire)

29voto

Jerry Points 383

Le code ci-dessous pourrait vous aider.

Pour résoudre ce problème complètement, je pense que nous avons besoin de quelque chose comme operator reload . Nous pouvons recharger des opérateurs comme '+ - / *', et vérifier si l'opérande est un nombre, si non, alors on lance Error.

En guise de solution partielle, lorsque JavaScript effectue une opération telle que "a + b", il appelle la fonction valueOf qui hérite de la méthode Object.prototype on peut réécrire Object.prototype.valueOf .

Object.prototype.originalValueOf = Object.prototype.valueOf;

Object.prototype.valueOf = function() {
  if (typeof this !== 'number') {
    throw new Error('Object is not a Number');
  }

  return this.originalValueOf();
}

var a = 1 + 2; // -> works
console.log(a); // -> 3

var b = {};
var c = b + 2; // -> will throw an Error

(indice : vous pouvez supprimer le code en production, et l'ajouter dans votre environnement de développement).

0 votes

C'est l'idéal ! Sur quel navigateur cela fonctionne-t-il ? Chrome et Safari, au moins, ne permettent pas de remplacer les prototypes natifs.

4 votes

Cela affecterait n'importe quel objet, pas seulement les nombres, et ce n'est donc pas quelque chose que vous voulez utiliser :(

0 votes

@Wesabi, je suis heureux d'avoir le coup de perf et je peux travailler autour des limitations si cela fonctionne. Malheureusement, je ne peux pas le faire.

11voto

La façon la plus propre de le faire est d'avoir une courte fonction pratique qui valide le résultat de l'expression à chaque fois.

je sais que ce n'est pas la réponse que tu cherches mais c'est la nature du javascript et tu ne peux pas le changer malheureusement.

function v(a){ if(isNaN(a)) throw "error"; return a; }
var test = v(100 * "abc");

0 votes

Je l'appellerais number ou quelque chose comme ça, mais cela semble être la solution la moins risquée

1 votes

typeof (100 * "abc") retours "number" parce que, ironiquement NaN est a Number . Vous voulez isNaN() .

3voto

War10ck Points 3872

Je sais que c'est un vieux fil de discussion mais je pense qu'il peut y avoir une réponse super simple à votre question. Vous pouvez soit créer une fonction pour l'instruction ci-dessous, soit l'ajouter en ligne.

JavaScript a des comportements uniques pour certaines valeurs. L'un de ces comportements uniques tourne autour de la valeur "not-a-number" ou NaN . La valeur de NaN ne sera pas égal à toute autre valeur, y compris NaN même. C'est pourquoi la déclaration suivante :

if(x != x) {
    throw "Value is NaN!";
}

sera vrai si et seulement si la valeur de x es NaN .

0 votes

Le site isNaN est un meilleur moyen de vérifier cela, mais la question porte sur un moyen d'interrompre le débogueur lorsqu'un NaN est produit.

2voto

EnglishMaster Points 984

Je pense que c'est une situation où le getter et le setter sont utiles.

Voici un exemple de code fictif pour vous donner une idée.

//Inside your Object class code.
function getPosition() {

  //You don't want the property "position" to be NaN, right?
  if(isNaN(this.position)) 
    throws "NaN is not a correct numerical value!";

  return this.position;

}

//Somewhere in your code
var newPosition = object.getPosition() + 1; //raises an exception.

Je pense que c'est mieux que d'implémenter une fausse surcharge d'opérateurs et de rendre les choses plus compliquées.

0 votes

Je suis d'accord sur les getters et setters, mais vous ne devriez pas vous attendre à ce que isNaN pour être une méthode de n'importe quoi et appeler anything.isNaN() lèvera automatiquement une exception

0 votes

Ouais, désolé. Mais c'est juste un psuedo code pour te donner une idée.

0 votes

isFinite est une autre fonction pratique. Parfois, vous voulez éviter de passer dans des choses comme Infinity o -Infinity !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X