Underscore: _.isNumber(NaN) gibt wahr zurück

Erstellt am 15. Dez. 2011  ·  38Kommentare  ·  Quelle: jashkenas/underscore

Da NaN für "Not a Number" steht, scheint die isNumber-Prüfung in diesem Fall false zurückzugeben. Ich merke aus anderen Diskussionen, dass dies tatsächlich Absicht ist. Vielleicht sollte die Dokumentation diese Tatsache explizit widerspiegeln.

enhancement fixed

Hilfreichster Kommentar

Ok, also habe ich mit einem einfachen Problem angefangen. Ich habe Eingaben, die Zeichenfolgen, Zahlen und möglicherweise NaN sind. Ich habe eine einfache Lösung in Basis-JavaScript mit parseInt und isFinite, um zu testen, ob das Parsen int erfolgreich ist. Einfach, aber nicht vollständig sauber oder selbsterklärend für mein Ziel. Also beschließe ich, meine total tolle Goto-Bibliothek für diese Art von Aufgaben zu verwenden. Bei der Erstinspektion finde ich eine Funktion, die sagt, dass sie einen Wert akzeptiert und Ihnen mitteilt, ob es sich um eine Zahl handelt, was nach meiner allgemeinen Definition das ist, was ich meiner Meinung nach will.

Sehen Sie hier zunächst, wie das Hinzufügen einer Zeile zur Dokumentation den Benutzern der Bibliothek helfen würde, beim ersten Mal die richtige Funktion für den Job zu erhalten? Zweitens bitte ich noch einmal um ein Beispiel, wo dies sinnvoll ist.

Es klingt, als wüssten Sie alles, was Sie über die Sprache wissen müssen. Anstatt also blindlings in die Dunkelheit Lösungen zu spucken, die mir mein Bruder aus der 8. Vielen Dank für Ihre Zeit.

Alle 38 Kommentare

Du hast Recht, es ist Absicht. Und ich denke, es muss nicht explizit erwähnt werden. Jeder, der schon einmal mit IEEE 754 Floats gearbeitet hat, weiß wahrscheinlich, dass NaN nur ein weiterer Gleitkommawert ist.

Verwandte: Diskussion in #321

Meine Frage ist, dass bei allgemeinen Webaufgaben eine Funktion namens isNumber eine gute Möglichkeit zu sein scheint, um zu überprüfen, ob ein gefundener Wert der allgemeinen Benutzerdefinition von "Ist dies eine Zahl?" entspricht.

Außerdem scheint mir, dass der NaN-Wert in erster Linie eingeführt wurde, um Werte zu identifizieren, die Berechnungen unterbrechen. Im Sinne der Spezifikation scheint es die richtige Antwort zu sein, wenn Sie die Frage "Ist das eine Zahl?" stellen. ist in der Tat, dass es "Keine Zahl" ist. Wenn Sie ein häufiges Beispiel nennen können, bei dem Sie möchten, dass die Antwort auf diese Frage wahr ist, halte ich jetzt die Klappe :)

Sie suchen nach isFinite , die Leute, die JS kennen, bereits kennen sollten.

Ok, also habe ich mit einem einfachen Problem angefangen. Ich habe Eingaben, die Zeichenfolgen, Zahlen und möglicherweise NaN sind. Ich habe eine einfache Lösung in Basis-JavaScript mit parseInt und isFinite, um zu testen, ob das Parsen int erfolgreich ist. Einfach, aber nicht vollständig sauber oder selbsterklärend für mein Ziel. Also beschließe ich, meine total tolle Goto-Bibliothek für diese Art von Aufgaben zu verwenden. Bei der Erstinspektion finde ich eine Funktion, die sagt, dass sie einen Wert akzeptiert und Ihnen mitteilt, ob es sich um eine Zahl handelt, was nach meiner allgemeinen Definition das ist, was ich meiner Meinung nach will.

Sehen Sie hier zunächst, wie das Hinzufügen einer Zeile zur Dokumentation den Benutzern der Bibliothek helfen würde, beim ersten Mal die richtige Funktion für den Job zu erhalten? Zweitens bitte ich noch einmal um ein Beispiel, wo dies sinnvoll ist.

Es klingt, als wüssten Sie alles, was Sie über die Sprache wissen müssen. Anstatt also blindlings in die Dunkelheit Lösungen zu spucken, die mir mein Bruder aus der 8. Vielen Dank für Ihre Zeit.

Mich interessiert, was @jashkenas denkt. Ich will nicht beleidigend oder herablassend klingen. Ich weiß, dass ich manchmal so rüber komme. Ich denke, es ist die Tatsache, dass ich versuche, das Gespräch in eine Richtung zu lenken, die das Problem besser zeigt, indem ich diese einfachen Antworten gebe und sehe, wie sie das Problem in Ihren Augen nicht lösen.

Sehen Sie hier zunächst, wie das Hinzufügen einer Zeile zur Dokumentation den Benutzern der Bibliothek helfen würde, beim ersten Mal die richtige Funktion für den Job zu erhalten?

Möglicherweise, sicher.

Zweitens bitte ich noch einmal um ein Beispiel, wo dies sinnvoll ist.

Testen für [[Klasse]] == "Nummer"? Das sollte klar sein, es stimmt mit Zahlen überein. Vielleicht sind es keine natürlichen Zahlen oder ganze Zahlen oder endliche Zahlen oder reelle Zahlen oder rationale Zahlen oder was auch immer Sie erwartet haben, aber es sind sicherlich alle Zahlen.

Trotzdem kann es manchmal schädlich sein, zu viel Flusen in der Dokumentation hinzuzufügen. Aber ich glaube nicht, dass dies eine dieser Zeiten ist. Dies könnte möglicherweise für Entwickler hilfreich sein, die in ihrem aktuellen Zustand möglicherweise eine widersprüchliche Interpretation des abstrakten Konzepts einer Zahl haben. Wie in Ihrem Fall, wo Sie bereits ein mentales Modell der Menge erstellt hatten, für die Sie testen wollten, und dann eine Funktion gefunden hatten, die _scheinbar_ war, um diesen Test durchzuführen. +1 , obwohl ich immer noch daran interessiert bin, was @jashkenas denkt.

Ja -- es ist überhaupt nicht offensichtlich, ob _.isNumber true oder false wenn NaN . Ich würde mich sicherlich nicht daran erinnern, es nicht ausprobiert zu haben. Hinweis zur Dokumentation im obigen Commit hinzugefügt. Vielen Dank.

Danke Leute. Es ist schön zu wissen, dass jemand anderes möglicherweise nicht auf dasselbe Problem stößt.

Dies scheint definitiv ein Fall zu sein, in dem Semantik technische Fakten übertrumpfen sollte. Ja, NaN kann nach einigen Spezifikationen eine Zahl sein. Aber wenn ich etwas stelle die Frage "Bist du eine Nummer?" und es sagt "Ich bin keine Nummer", dann sollte ich es glauben. Keine Zahl – NaN – ist definitiv keine Zahl... und isNumber sollte false zurückgeben.

Das Gotcha in die Dokumente zu packen – anstatt Dinge so zu reparieren, dass sie für den Menschen Sinn machen – führt zu weniger Zeit beim Codieren und mehr Zeit beim Blicken über die Dokumentation, die sich am Kopf kratzt.

Kann das bitte nochmal überdacht werden?

@contentfree : NaN ist Mitglied der Floats. Jede Zahl in JS ist ein Float. Ich denke, das macht NaN so zahlreich wie es nur geht. NaN bedeutet nicht "Ich bin keine Nummer". Es ist die numerische Darstellung von Nicht-Zahlen. Fall in meinem Buch geschlossen. Verwenden Sie isFinite wenn Sie auf Zahlen testen möchten, die nicht NaN / Infinity / -Infinity .

Nicht um ein totes Pferd zu schlagen, aber...

Warum nicht einfach
obj instanceOf Number

Mir scheint, dass, wenn es eine lesbarere Möglichkeit gibt, die erforderliche Aktion auszuführen, die bereits in der Javascript-Spezifikation vorhanden ist, ich es auf diese Weise tun werde, ohne eine Bibliothek mit einer unbekannten Bibliothek zu verwenden (es sei denn, ich verschwende Zeit mit der Untersuchung) Bibliothek.

Ich stimme dafür, dass wir, wenn wir dies nicht als semantisch korrekt beheben, einfach den nutzlosen Overhead und die Kopfschmerzen aus der Bibliothek entfernen sollten.

Der Operator instanceof funktioniert nur für Objekte, nicht für Primitive: new Number(5) instanceof Number == true; 5 instanceof Number == false . Es funktioniert auch nicht über Frames in Browsern. [[Class]] Überprüfung über Object::toString wird allgemein als die zuverlässigste Methode zur Typüberprüfung in JavaScript angesehen.

+1, um die Bibliothek nützlicher zu machen und gleichzeitig Benutzer, die neu in JavaScript sind, zu schulen.

Anregung:
_.isNumber(Objekt, [isFinite]);

Dies ermöglicht ein einfaches Hinzufügen eines True zu Ihrer aktuellen Implementierung, wenn Sie von diesem Fallstrick erwischt werden, während Sie erfahren, dass isFinite wahrscheinlich das war, wonach Sie in erster Linie gesucht haben.

Mein 2c

@nickl- Interessante Idee, aber ... warum nicht in diesem Fall einfach isFinite ?

Da _.isNaN bereits existiert, könnte alternativ _.isFinite aus Symmetriegründen hinzugefügt werden:

_.isFinite = function (value) {
  return value > -1 / 0 && value < 1 / 0;
};

@kitcambridge

Das einzige Problem, das ich damit sehe, ist, dass Strings als endliches "0x0", "0xF", "2" usw. übergeben werden. Egal was, es muss mit _.isNumber oder einem Äquivalent kombiniert werden:

_.isFinite = function (obj) {
  return obj > -1/0 && obj < 1/0 && _.isNumber(obj);
};

Kann fünf Zeichen mit val === +val für Zahlentests abschneiden:

_.isFinite = function (obj) {
  return obj > -1/0 && obj < 1/0 && obj === +obj;
};

@octatone Sicher, ich denke, das ist fair ... technisch gesehen sind diese Strings _sind_ endlich, da sie in numerischen Vergleichen verwendet werden können (der Interpreter sollte sie zu Zahlen zwingen), aber Ihr Vorschlag ist konsistenter mit den vorhandenen Underscore-Typüberprüfungsfunktionen.

Was ist mit _,isValidNumber, das inline mit dem vorhandenen _.isValidDate ist und das isFinite-Argument nicht verwechselt?

@nickl-

NaN und Infinity _sind_ gültige Zahlen. Ich denke, dass die Benennung dieser Funktion als isValidNumber ihren Zweck verwirren würde, oder meinen Sie, dass Sie isNumber in isValidNumber umbenennen?

NaN und Infinity _sind_ gültige Zahlen. Ich denke, die Benennung dieser Funktion isValidNumber würde ihren Zweck verwirren.

Ich stimme zu.

Umbenennen habe ich nicht gesagt...

Ich war auch überrascht, dass _.isNumber(NaN) === true .

Ich glaube, ich tendiere dazu, @contentfrees https://github.com/jashkenas/underscore/issues/406#issuecomment -4144992 zuzustimmen. Im Software-Engineering haben wir sogar für diesen speziellen Fall ein Prinzip: Das Prinzip des geringsten Erstaunens . ;-)

Und nachdem ich so viele Leute verwirrt habe, denke ich, dass es sinnvoll wäre, die Funktion so zu gestalten, dass sie das tut, was Menschen von Nicht-Hardcore-js-Programmierern erwarten, wenn sie sich ihren Namen ansehen.

Nur mein kleiner 2¢…™

_.isNaN ist auch verwirrend. Im Dokument:

Hinweis: Dies ist nicht dasselbe wie die native isNaN-Funktion, die auch für viele andere Nicht-Zahlenwerte, wie z. B. undefined, true zurückgibt.

im normalen Sinne ist undefined tatsächlich eine Not-A-Number.

Ich stimme für semantische Konstruktivität, isNumber == Not a number lol. Ich glaube, wenn Sie ins Detail gehen müssen, um auf Gleitkommawerte zu prüfen, dann tun Sie dies auf eine andere Weise?

Ich stimme für semantische Konstruktivität,

Nein, es ist eine Zahl von [[Class]] genau wie -Infinity , Infinity , & Object(2) . Es ist eines dieser Dinge, die Entwickler lernen, wie Funktionen auch Objekte sind. Es besteht die Möglichkeit, dass Sie eine Form der Validierung Ihrer Nummer durchführen möchten, die für diese Methode nicht zulässig ist. Ist sie beispielsweise größer als -1 , kleiner als Math.pow(2,32) oder eine ganze Zahl. In Fällen von -Infinity , Infinity oder NaN ich _.isFinite als Validator. Ebenso wird _.isDate nicht validiert, wenn das Datumsobjekt ein gültiges Datum darstellt.

Wie wäre es mit der Aktualisierung der Dokumentation mit einem "siehe auch: isFinite" und "siehe auch: «Essay-Aufzählungsmethoden zur Bestimmung, ob etwas ein numerischer Wert ist, den Sie tatsächlich verwenden können»"

@michaelficara Ich weiß, dass NaN in der Spezifikation ein sehr numerischer Typ ist. Aber denkt ein Programmierer das, wenn er fragt, ob das eine Zahl ist?

Was die meisten von uns meistens wissen möchten, ist, kann ich dies für grundlegende Arithmetik verwenden. Sie müssen also isNumber(x) && isFinite(x) gehen. Und das ist in Ordnung, denke ich. Aber es ist ein großes Problem für einen neuen Programmierer und liest sich nicht gut.

Aus rein englischsprachiger Sicht macht Not a Number (NaN), die bei einem Test namens isNumber true zurückgibt, überhaupt keinen Sinn. Wäre dies nicht besser isNumeric oder isNumericType?

Ich habe keinen Zweifel, dass dies Fehler hinzufügen und viele Stunden verschwenden wird, zumindest wenn die Leute zum ersten Mal darauf stoßen.

Sie müssen also isNumber(x) && isFinite(x) gehen.

Ich habe kürzlich eine Implementierung von _.isFinite angepasst , um ES6
Es stellt sicher, dass der Wert ein Zahlenprimitiv ist, endlich ist und diesen allgemeinen Fall behandeln sollte.

Es ist nicht erforderlich, das Verhalten von _.isNumber zu ändern, das mit den anderen [[Class]] Prüfmethoden übereinstimmt.

Aus rein englischsprachiger Sicht macht Not a Number (NaN), die bei einem Test namens isNumber true zurückgibt, überhaupt keinen Sinn. Wäre dies nicht besser isNumeric oder isNumericType?

Siehe meinen Kommentar zur Validierung, _.isNumber und _.isDate .

@jdalton Sie haben

Aber es scheint einfach so kontraintuitiv zu sein, dass etwas, das keine Zahl genannt wird, eine Zahl ist.

@Walms stimmen zu 100% zu. Ich denke, in diesem Fall sollten der Programmierer und die Intuition die absolute "Korrektheit" der Anweisung überstimmen, wenn NaN _technisch_ numerisch ist.

Aber es scheint einfach so kontraintuitiv zu sein, dass etwas, das keine Zahl genannt wird, eine Zahl ist.

Ist es in diesem Zusammenhang widersinniger als _.isNumber true für Zahlenobjekte zurückzugeben, Object(2) die vom Typ object ?

Dies sind [[Class]] Methoden. Vielleicht muss das in der Dokumentation deutlicher gemacht werden.

Ich habe bereits eine brauchbare Alternative vorgeschlagen, nämlich _.isFinite einfach ES6 Number.isFinite folgen zu lassen. Wenn Sie ein einfaches is-number möchten, verwenden Sie typeof x == 'number' . Wenn Sie eine Bestätigung wünschen, dass der Wert nicht NaN , Infinity oder -Infinity , alle [[Class]] von Number , dann _.isFinite ist der richtige Weg.

Suchen Sie unter Unterstrich-Beitrag nach feinkörnigeren Zahlenmethoden. Es hat _.isNumeric , _.isInteger , _.isZero , _.isEven , _.isOdd , _.isFloat , _.isNegative , & _.isPositive .

@jdalton Ich denke,

Ich habe anfangs nicht gesehen, dass _.isNumber einen Kontext erhält, indem ihm is vorangestellt wurde, was bedeutet, dass es sich um eine Typprüfung handelt. In diesem Kontext haben Sie völlig Recht, es macht keinen Sinn, dass _.isNumber für NaN false zurückgibt.

Aber dann scheinen underscore-contrib und isFinite diesen Kontext zu durchbrechen. Wie sie mit is beginnen, betrachten sie jedoch eher den Wert als den Typ. Und hier denke ich, dass die Verwirrung darin besteht, dass es keine klare Möglichkeit gibt, den Kontext aus dem Funktionsnamen zu bestimmen.

All dies sagte, ich sehe keine Möglichkeit, dies zu beheben.

Ich denke, das Problem hier ist, dass es einige Dinge an Zahlen gibt, die nicht intuitiv sind. Sie verhalten sich jedoch konsequent. Es wäre möglich, _.isNumber in diesem Fall intuitiver zu gestalten, indem man es weniger konsistent macht, was es in anderen Fällen letztendlich weniger intuitiv machen würde.

Hier einige konkrete Beispiele:

# If you add two Numbers together you always get another Number back
# This function should always return true no matter what you pass it
closedUnderAddition = (a, b) -> !isNumber(a) || !isNumber(b) || isNumber(a + b)

closedUnderAddition(1,1) == true
closedUnderAddition(Number.MAX_INT,2**970) == true # false if isNumber checks finiteness

# If you divide two Numbers you always get another Number back
closedUnderDivision = (a, b) -> !isNumber(a) || !isNumber(b) || isNumber(a / b)

closedUnderDivision(1, 2) == true
closedUnderDivision(1, 0) == true # false if isNumber checks finiteness
closedUnderDivision(0, 0) == true # false if isNumber checks finiteness or NaN-ness

# Anything you cast to a Number is a Number
castsToNumber = (x) -> isNumber(Number(x))

castsToNumber(1) == true
castsToNumber(Infinity) == true # false if isNumber checks finiteness
castsToNumber("bees") == true # false if isNumber checks finiteness or NaN-ness
castsToNumber("3") == true

Wie Michaelficarra sagte:

NaN bedeutet nicht "Ich bin keine Nummer". Es ist die numerische Darstellung von Nicht-Zahlen.

Oder anders ausgedrückt, es gibt "Zahlen" und Zahlen. NaN ist vielleicht keine "Zahl", aber es ist absolut eine Zahl zusammen mit Infinity, -Infinity und lächerlichen Dingen wie -0. So wild und wollig es auch ist, die Definition von Number ist gut spezifiziert und verhält sich konsistent.

"Zahl" auf der anderen Seite ist ein schlecht definiertes Konzept, das, je nachdem, mit wem Sie sprechen, eines oder keines der oben genannten enthalten kann , und möglicherweise numerische Zeichenfolgen, Bools, Mitternacht und alle möglichen Dinge. Das ist in Ordnung, aber es wird nie eine Lösung geben, die jedermanns Definition entspricht.

Ich denke, aus diesem Grund ist dies im Wesentlichen ein Dokumentationsproblem.

Hat "Zahl" auch aufgehört, für andere wie ein Wort auszusehen?

Gute Punkte, @sgentle. Ich stimme für Konsistenz über Intuitivität, da ersteres ein objektives Maß ist, während wir uns nicht alle darüber einig sind, was intuitiv ist (wie dieser Thread zeigt).

Behandeln Sie NaN einfach nicht als "Keine Zahl". NaN ist ein besonderer Wert.

Behandeln Sie NaN einfach nicht als "Keine Zahl". NaN ist ein besonderer Wert.

Ja, aber es heißt "Keine Nummer".
Für mich ist das so
var _false = "wahr";
Ja, Sie können lernen, dass _false wahr ist, aber es ist ohne guten Grund verwirrend.

@ Walms Es ist ein schlechter Name, aber das ist nicht die Schuld von JS. Wir können den Typen beschuldigen, der es als "NaN" bezeichnet hat. http://en.wikipedia.org/wiki/NaN

Aargh, ich wünschte, _.isNumber(NaN) würde false ... hier drüben ernsthaft am Kopf kratzen, bis mir klar wurde, dass dies der Grund war.

if (isNaN(Number(value))) {
  alert('Number required.');
}

@pspi Einverstanden. Wenn sich _.isNumber() im _semantischen_ Sinne korrekt verhält, bedeutet das, dass ich es nie wirklich verwenden werde. ._isFinite() scheint die Funktion zu sein, die so funktioniert, wie ich es erwarten würde.

Und natürlich entdecke ich einen Tag, nachdem ich dies gepostet habe, dass _.isFinite('1') true , obwohl das Argument keine Zahl ist.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

arypbatista picture arypbatista  ·  3Kommentare

clouddueling picture clouddueling  ·  3Kommentare

acl0056 picture acl0056  ·  5Kommentare

xiaoliwang picture xiaoliwang  ·  3Kommentare

githublyp picture githublyp  ·  3Kommentare