Mengapa `null> = 0 && null <= 0` tetapi tidak` null == 0`?

142

Saya harus menulis rutin yang menambah nilai variabel dengan 1 jika tipenya adalah numberdan memberikan 0 ke variabel jika tidak, di mana variabel awalnya nullatau undefined.

Implementasi pertama adalah v >= 0 ? v += 1 : v = 0karena saya pikir sesuatu yang bukan angka akan membuat ekspresi aritmatika salah, tetapi itu salah karena null >= 0dievaluasi benar. Kemudian saya belajar nullberperilaku seperti 0 dan ekspresi berikut semuanya dievaluasi menjadi benar.

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

Tentu saja, nullbukan 0. null == 0dievaluasi salah. Ini membuat ekspresi yang tampaknya tautologis (v >= 0 && v <= 0) === (v == 0)salah.

Mengapa nullseperti 0, meskipun sebenarnya bukan 0?

C. Lee
sumber
3
Dia berbicara tentang Javascript. Contoh Anda dalam PHP. Dalam operator PHP == membandingkan nilai dengan cara khusus. Anda dapat membuat beberapa perbandingan yang benar-benar gila seperti "10" == "1e1" (yang benar). Jika Anda menggunakan operator ===, Anda akan mendapatkan hasil yang berbeda karena memeriksa apakah jenisnya cocok dengan nilainya. Lihat tautan ini: php.net/manual/en/language.operators.comparison.php
Pijusn
Operator PHP '==' benar-benar berfungsi dengan cara "khusus".
Alchemist Dua-Bit
Jika kebutuhan Anda adalah mulai menghitung pada 1 dan bukannya 0, ada cara yang sangat singkat untuk meningkatkan penghitung yang awalnya nullatau undefined:c = -~c // Results in 1 for null/undefined; increments if already a number
Ates Goral
1
undefinedadalah nilai variabel, untuk variabel yang belum diinisialisasi. null, di sisi lain, adalah nilai objek kosong, dan tidak boleh dicampur dengan angka. nulltidak boleh digabungkan dengan angka, jadi null tidak harus berperilaku seperti angka.
Matius
1
@AtesGoral - singkat, tetapi tidak jelas. Layak diingatkan orang bahwa setiap kali melakukan sesuatu yang tidak jelas, untuk menambahkan komentar menjelaskan apa yang dilakukan kode Dalam kebanyakan situasi, saya akan menganggapnya sebagai "optimasi prematur", mengingat bahwa itu memperdagangkan kejelasan untuk mendapatkan kinerja yang sangat kecil.
ToolmakerSteve

Jawaban:

207

Pertanyaan Anda yang sebenarnya tampaknya:

Mengapa:

null >= 0; // true

Tapi:

null == 0; // false

Apa yang sebenarnya terjadi adalah bahwa lebih besar-dari-atau-sama Operator ( >=), melakukan jenis paksaan ( ToPrimitive), dengan sedikit jenis Number, sebenarnya semua operator relasional memiliki perilaku ini.

nulldiperlakukan dengan cara khusus oleh Operator Persamaan ( ==). Singkatnya, itu hanya memaksa untuk undefined:

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

Nilai seperti false, '', '0', dan []tunduk jenis paksaan numerik, semua dari mereka memaksa ke nol.

Anda dapat melihat detail bagian dalam proses ini dalam Algoritma Perbandingan Kesetaraan Abstrak dan Algoritma Perbandingan Hubungan Abstrak .

Singkatnya:

  • Perbandingan Relasional: jika kedua nilai bukan tipe String, ToNumberdipanggil keduanya. Ini sama dengan menambahkan +di depan, yang untuk null koerces 0.

  • Perbandingan Kesetaraan: hanya memanggil ToNumberStrings, Numbers, dan Booleans.

CMS
sumber
1
Hai CMS, sesuai penjelasan Anda, nol primitif adalah 0, jadi 0> = 0 mengembalikan true dan == mengembalikan false.but sesuai dengan algoritma ecma Jika Jenis (x) adalah Obyek dan Jenis (y) adalah String atau Angka, kembalikan hasil perbandingan ToPrimitive (x) == y.Kemudian dalam ini harus mengembalikan true.please jelaskan saya
bharath muppa
bagi saya jawabannya tidak memberikan jawaban - null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:- dan apa? Bisakah Anda menjelaskan, mengapa null >= 0? :)
Andrey Deineko
@bharathmuppa @ andrey-deineko: Sisa jawaban CMS ada di sini: Algoritma Perbandingan Relasional Abstrak yang menjelaskan pada poin 3. bahwa jika kedua nilai bukan tipe String, ToNumber dipanggil pada keduanya. Ini sama dengan menambahkan +di depan, yang untuk null koerces 0. Kesetaraan hanya memanggil ToNumber on Strings, Numbers, dan Booleans.
Michael Liquori
7
Deskripsi yang bagus, tapi saya tidak suka itu. Dalam bahasa apa pun (x == 0 || x> 0) harus sama dengan (x> = 0). javascript adalah bahasa yang bodoh.
John Henckel
1
Benar-benar bug dalam spec (karena secara matematis itu salah) dan tidak ada yang bisa dilakukan karena jutaan situs web mengandalkan perbandingan nol ^^ '
mahieddine
14

Saya ingin menyampaikan pertanyaan untuk lebih meningkatkan visibilitas masalah:

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

Itu tidak masuk akal. Seperti bahasa manusia, hal-hal ini perlu dipelajari dengan hati.

estani
sumber
1
Seperti yang dijelaskan di atas dapat dijelaskan dengan pengecualian sebagai = = memperlakukan null, jika tidak dalam semua kasus null dikonversi menjadi 0 dengan menggunakan Number (nulll)
Sourabh Ranka
5

JavaScript memiliki perbandingan yang ketat dan konversi tipe

null >= 0;itu benar tetapi (null==0)||(null>0)salah

null <= 0;itu benar tetapi (null==0)||(null<0)salah

"" >= 0 itu juga benar

Untuk perbandingan abstrak relasional (<=,> =), operan pertama dikonversi ke primitif, kemudian ke tipe yang sama, sebelum perbandingan.

typeof null returns "object"

Ketika tipe objek javascript mencoba untuk merender objek (yaitu null) langkah-langkah berikut diambil ( ECMAScript 2015 ):

  1. Jika PreferredTypetidak lulus, biarkan hint"default".
  2. Lain jika PreferredTypeadalah hintString, biarkan hint"string".
  3. Lain PreferredTypeadalah hintAngka, biarlah hint"angka".
  4. Biarkan exoticToPrimsaja GetMethod(input, @@toPrimitive).
  5. ReturnIfAbrupt(exoticToPrim).
  6. Jika exoticToPrimtidak ditentukan, maka
    a) Biarkan hasilnya Call(exoticToPrim, input, «hint»).
    b) ReturnIfAbrupt(result).
    c) Jika Type(result)bukan Objek, kembalikan hasil.
    d) Melempar pengecualian TypeError.
  7. Jika hint"default", biarkan hint"angka".
  8. Kembali OrdinaryToPrimitive(input,hint).

Nilai yang diizinkan untuk petunjuk adalah "default", "number", dan "string". Objek tanggal, adalah unik di antara objek ECMAScript bawaan karena mereka memperlakukan "default" sebagai setara dengan "string". Semua objek ECMAScript bawaan lainnya memperlakukan "default" sebagai setara dengan "angka" . ( ECMAScript 20.3.4.45 )

Jadi saya pikir nullmengkonversi ke 0.

Panos Kal.
sumber
1

Saya punya masalah yang sama !!. Saat ini satu-satunya solusi saya adalah memisahkan.

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 !
jon
sumber
Mungkin lebih jelas untuk bukan melakukan: if (a!=null && a>=0). Ini mengklarifikasi alasan untuk tidak hanya melakukan >=sendiri: "a mungkin nol (atau tidak terdefinisi, yang juga '== null')".
ToolmakerSteve
0
console.log( null > 0 );  // (1) false
console.log( null == 0 ); // (2) false
console.log( null >= 0 ); // (3) true

Secara matematis, itu aneh. Hasil terakhir menyatakan bahwa "nol lebih besar dari atau sama dengan nol", jadi dalam salah satu perbandingan di atas pasti benar, tetapi keduanya salah.

Alasannya adalah bahwa pemeriksaan kesetaraan ==dan perbandingan > < >= <=bekerja secara berbeda. Perbandingan mengonversi nol ke angka, memperlakukannya sebagai 0. Itu sebabnya (3) null >= 0adalah truedan (1) null > 0adalah false.

Di sisi lain, cek kesetaraan ==untuk undefineddan nulldidefinisikan seperti itu, tanpa konversi, mereka sama satu sama lain dan tidak apa-apa sama lain. Itu sebabnya (2) null == 0adalah false.

S. Hesam
sumber