Perché `null> = 0 && null <= 0` ma non` null == 0`?


142

Ho dovuto scrivere una routine che incrementa il valore di una variabile di 1 se il suo tipo è numbere assegna 0 alla variabile in caso contrario, dove la variabile è inizialmente nullo undefined.

La prima implementazione è stata v >= 0 ? v += 1 : v = 0perché pensavo che qualcosa di diverso da un numero non avrebbe reso falsa un'espressione aritmetica, ma era errata poiché null >= 0è stata valutata come vera. Quindi ho imparato che nullsi comporta come 0 e le seguenti espressioni sono tutte valutate come vere.

  • null >= 0 && null <= 0
  • !(null < 0 || null > 0)
  • null + 1 === 1
  • 1 / null === Infinity
  • Math.pow(42, null) === 1

Naturalmente, nullnon null == 0è 0. viene valutato come falso. Ciò rende (v >= 0 && v <= 0) === (v == 0)falsa l' espressione apparentemente tautologica .

Perché è nullcome 0, anche se in realtà non è 0?


3
Sta parlando di Javascript. Il tuo esempio è in PHP. Nell'operatore PHP == confronta i valori in modo speciale. Puoi fare paragoni davvero folli come "10" == "1e1" (che è vero). Se si utilizza operator ===, si otterrà un risultato completamente diverso perché controlla se il tipo corrisponde e il valore. Controllare questo link out: php.net/manual/en/language.operators.comparison.php
Pijusn

L'operatore PHP '==' funziona davvero in modo "speciale".
Two-Bit Alchemist

Se il tuo requisito era iniziare a contare da 1 invece di 0, c'è un modo davvero conciso per incrementare i contatori che inizialmente sono o nullo undefined:c = -~c // Results in 1 for null/undefined; increments if already a number
Ates Goral

1
undefinedè un valore variabile, per le variabili che non sono state inizializzate. nulld'altra parte, è un valore di oggetto vuoto e non deve essere miscelato con numeri. nullnon dovrebbe essere combinato con numeri, quindi null non dovrebbe comportarsi come numeri.
Matteo

1
@AtesGoral - conciso, ma non ovvio. Vale la pena ricordare alle persone che ogni volta che si fa qualcosa di non ovvio, si prega di aggiungere un commento che spieghi cosa fa il codice. Nella maggior parte dei casi, lo considero una "ottimizzazione prematura", dato che scambia chiarezza per un minuscolo aumento delle prestazioni.
ToolmakerSteve

Risposte:


207

La tua vera domanda sembra essere:

Perché:

null >= 0; // true

Ma:

null == 0; // false

Ciò che accade realmente è che l' Operatore maggiore ( o uguale>= ) ( ) esegue la coercizione di tipo ( ToPrimitive), con un tipo di suggerimento di Number, in realtà tutti gli operatori relazionali hanno questo comportamento.

nullviene trattato in modo speciale dall'operatore Equals ( ==). In breve, costringe solo a undefined:

null == null; // true
null == undefined; // true

Valore, ad esempio false, '', '0'e []sono soggetti a coercizione di tipo numerico, tutti costringere a zero.

Puoi vedere i dettagli interni di questo processo in The Abstract Equality Comparison Algorithm e The Abstract Relational Comparison Algorithm .

In sintesi:

  • Confronto relazionale: se entrambi i valori non sono di tipo String, ToNumberviene chiamato su entrambi. Questo è lo stesso dell'aggiunta di un +fronte, a cui per i valori nulli viene forzato 0.

  • Confronto di uguaglianza: chiama solo ToNumberstringhe, numeri e valori booleani.


1
Ciao CMS, come da spiegazione la primitiva nulla è 0, quindi 0> = 0 restituisce true e == restituisce false.ma secondo l'algoritmo ecma Se Type (x) è Object e Type (y) è String o Number, restituisce il risultato del confronto ToPrimitive (x) == y. quindi in questo dovrebbe restituire true.Per favore spiegami
bharath muppa

per me la risposta non fornisce una risposta - null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:- e cosa? Puoi spiegare, perché null >= 0? :)
Andrey Deineko il

@bharathmuppa @ andrey-deineko: Il resto della risposta di CMS è qui: l'algoritmo di confronto relazionale astratto che spiega al punto 3. che se entrambi i valori non sono di tipo String, ToNumber viene chiamato su entrambi. Questo è lo stesso dell'aggiunta di un +fronte, a cui per i valori nulli viene forzato 0. L'uguaglianza chiama ToNumber solo su stringhe, numeri e valori booleani.
Michael Liquori,

7
Buona descrizione, ma non mi piace. In qualsiasi lingua (x == 0 || x> 0) dovrebbe essere equivalente a (x> = 0). javascript è un linguaggio stupido.
John Henckel,

1
È semplicemente un bug nelle specifiche (perché matematicamente è sbagliato) e non c'è nulla da fare al riguardo poiché milioni di siti Web si basano su confronti nulli ^^ '
mahieddine

14

Vorrei estendere la domanda per migliorare ulteriormente la visibilità del problema:

null >= 0; //true
null <= 0; //true
null == 0; //false
null > 0;  //false
null < 0;  //false

Non ha senso. Come le lingue umane, queste cose devono essere apprese a memoria.


1
Come descritto sopra, può essere spiegato con una sola eccezione come how == tratta null, altrimenti in tutti i casi null viene convertito in 0 utilizzando Number (nulll)
Sourabh Ranka

5

JavaScript ha confronti sia rigorosi che di conversione dei tipi

null >= 0;è vero ma (null==0)||(null>0)è falso

null <= 0;è vero ma (null==0)||(null<0)è falso

"" >= 0 è anche vero

Per i confronti astratti relazionali (<=,> =), gli operandi vengono prima convertiti in primitivi, quindi nello stesso tipo, prima del confronto.

typeof null returns "object"

Quando type è object, javascript tenta di stringere l'oggetto (cioè null) vengono prese le seguenti fasi ( ECMAScript 2015 ):

  1. Se PreferredTypenon è stato passato, hintsia "predefinito".
  2. Altrimenti se PreferredTypeè hintString, hintsia "stringa".
  3. Altrimenti PreferredTypeè hintNumero, hintsia "numero".
  4. Lascia exoticToPrimstare GetMethod(input, @@toPrimitive).
  5. ReturnIfAbrupt(exoticToPrim).
  6. Se exoticToPrimnon è indefinito,
    a) Lascia che sia il risultato Call(exoticToPrim, input, «hint»).
    b) ReturnIfAbrupt(result).
    c) Se Type(result)non è Object, restituisce il risultato.
    d) generare un'eccezione TypeError.
  7. Se hintè "predefinito", hintsia "numero".
  8. Ritorno OrdinaryToPrimitive(input,hint).

I valori consentiti per il suggerimento sono "default", "numero" e "stringa". Gli oggetti data, sono univoci tra gli oggetti ECMAScript incorporati in quanto trattano "default" come equivalente a "stringa". Tutti gli altri oggetti ECMAScript incorporati considerano "default" come equivalente a "numero" . ( ECMAScript 20.3.4.45 )

Quindi penso che nullconverta in 0.


1

Ho avuto lo stesso problema !!. Attualmente la mia unica soluzione è separare.

var a = null;
var b = undefined;

if (a===0||a>0){ } //return false  !work!
if (b===0||b>0){ } //return false  !work!

//but 
if (a>=0){ } //return true !

Potrebbe essere più chiaro di fare, invece: if (a!=null && a>=0). Questo chiarisce il motivo per cui non si fa semplicemente >=da solo: "a potrebbe essere nullo (o indefinito, che è anche '== null')".
ToolmakerSteve

0
console.log( null > 0 );  // (1) false
console.log( null == 0 ); // (2) false
console.log( null >= 0 ); // (3) true

Matematicamente, è strano. L'ultimo risultato afferma che "null è maggiore o uguale a zero", quindi in uno dei confronti sopra deve essere vero, ma sono entrambi falsi.

Il motivo è che un controllo di uguaglianza ==e confronti > < >= <=funzionano diversamente. I confronti convertono null in un numero, trattandolo come 0. Ecco perché (3) null >= 0è truee (1) null > 0è false.

D'altra parte, il controllo di uguaglianza ==di undefinede nullè definito in modo che, senza alcuna conversione, sono uguali tra loro e non fanno uguale altro. Ecco perché (2) null == 0è false.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.