Dalam JavaScript, mengapa "0" sama dengan false, tetapi ketika diuji dengan 'jika' itu tidak salah dengan sendirinya?

232

Berikut ini menunjukkan yang "0"salah dalam Javascript:

>>> "0" == false
true

>>> false == "0"
true

Jadi mengapa cetak berikut ini "ha"?

>>> if ("0") console.log("ha")
ha
nonopolaritas
sumber
47
"0"adalah string, dan karena itu tidak kosong, itu dievaluasi ke true.
Digital Plane
8
"0" === false [...] false
3
Lihat kebenaran artikel Angus Croll dalam javascript. javascriptweblog.wordpress.com/2011/02/07/...
timrwood
8
'0'==falsetapi '0' bukan nilai falsey (ya Javascript bisa aneh)
Linsey
5
@Linsey: Seluruh hal "palsu" dan "benar" hanya pernah dimaksudkan untuk menjelaskan bagaimana nilai dikonversi menjadi boolean. Ketika Anda membandingkan dua nilai dengan ==, mereka tidak pernah dikonversi menjadi boolean, jadi itu tidak berlaku. (Aturan untuk konversi tampaknya mendukung konversi ke angka.)
milimoose

Jawaban:

251

Alasannya adalah karena ketika Anda melakukannya secara eksplisit "0" == false, kedua belah pihak sedang dikonversi ke angka, dan kemudian perbandingan dilakukan.

Ketika Anda melakukannya if ("0") console.log("ha"):, nilai string sedang diuji. Setiap string yang tidak kosong adalah true, sedangkan string yang kosong adalah false.

Sama dengan (==)

Jika kedua operan tidak dari jenis yang sama , JavaScript mengkonversi operan kemudian menerapkan perbandingan yang ketat. Jika salah satu operan adalah angka atau boolean , operan dikonversi menjadi angka jika memungkinkan; lain jika salah satu operan adalah string , operan lainnya dikonversi ke string jika memungkinkan. Jika kedua operan adalah objek , maka JavaScript membandingkan referensi internal yang sama ketika operan merujuk ke objek yang sama dalam memori.

(Dari Operator Perbandingan di Jaringan Pengembang Mozilla)

jdi
sumber
348

Tabel yang menampilkan masalah:

pernyataan jika benar

dan == perbandingan sebenarnya dari semua jenis objek dalam javascript

Moral cerita menggunakan === kesetaraan ketat menampilkan kewarasan

kredit pembuatan tabel: https://github.com/dorey/JavaScript-Equality-Table

Joe
sumber
2
Lebih masuk akal dengan urutan nilai lain gist.github.com/kirilloid/8165660
kirilloid
3
Mulai sekarang, jika seseorang mengatakan bahwa dia tidak pernah menggunakan operator perbandingan yang ketat, saya akan menghadapinya dengan tabel ini dan membuatnya menangis. Masih tidak yakin apakah saya memahami konsep itu NaN. Maksudku, typeof NaN // numbertapi NaN === NaN // false, hmm ...
Justus Romijn
4
Seorang teman saya membuat f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - grafik yang sama seperti di atas, tetapi sedikit lebih mudah dibaca.
Lucy Bain
@JustusRomijn ada beberapa nilai untuk diwakili NaN, jadi ketika Anda membandingkan 2 NaN, mereka memiliki nilai yang berbeda (saya kira). Baca kutipan pertama di sini .
cychoi
4
Tabel ini memiliki kesalahan. Baik ==atau ===Operator untuk [], {}, [[]], [0]dan [1]nilai-nilai tidak mengevaluasi untuk benar. Maksud saya [] == []dan [] === []juga salah.
Herbertusz
38

Ini sesuai dengan spec.

12.5 Pernyataan if 
.....

2. Jika ToBoolean (GetValue (exprRef)) benar, maka 
Sebuah. Kembalikan hasil evaluasi Pernyataan pertama.
3. Lain, 
....

ToBoolean, menurut spesifikasi, adalah

Operasi abstrak ToBoolean mengubah argumennya menjadi nilai tipe Boolean sesuai dengan Tabel 11:

Dan tabel itu mengatakan ini tentang string:

masukkan deskripsi gambar di sini

Hasilnya salah jika argumennya adalah String kosong (panjangnya nol); jika tidak, hasilnya benar

Sekarang, untuk menjelaskan mengapa "0" == falseAnda harus membaca operator kesetaraan, yang menyatakan itu mendapatkan nilainya dari operasi abstrak GetValue(lref)cocok dengan yang sama untuk sisi kanan.

Yang menggambarkan bagian yang relevan ini sebagai:

jika IsPropertyReference (V), maka 
Sebuah. Jika HasPrimitiveBase (V) salah, maka mari menjadi metode internal [[Get]], jika tidak, biarkan get
menjadi metode internal [[Get]] khusus yang didefinisikan di bawah ini. 
b. Kembali hasil memanggil metode internal get menggunakan basis sebagai nilai ini, dan lewat
GetReferencedName (V) untuk argumen

Atau dengan kata lain, string memiliki basis primitif, yang memanggil kembali metode get internal dan akhirnya tampak salah.

Jika Anda ingin mengevaluasi hal-hal menggunakan penggunaan operasi GetValue ==, jika Anda ingin mengevaluasi menggunakan ToBoolean, gunakan ===(juga dikenal sebagai operator kesetaraan "ketat")

Penyamaran
sumber
"a string has a primitive base, which calls back the internal get method and ends up looking false"Apakah ini benar untuk semua string?
aziz punjani
@Interstellar_Coder Section 8.12.3: [[Get]] (P)menjelaskan cara kerjanya. Memang benar hanya untuk case yang stringnya 0, seperti halnya sekelompok panggilan internal lainnya yang akhirnya menghasilkan GetOwnPropertyyang melihat bahwa "apa pun" adalah properti data, yang kemudian mengembalikan semua jalan kembali nilai itu. Inilah mengapa "0" salah, dan "bla" benar. Lihat beberapa video Douglas Crockford di teater pengembang Yahoo, ia menggambarkan "kebenaran" dalam JavaScript sedikit kurang kompleks daripada saya. Jika Anda mengerti apa arti "benar" dan "salah", Anda akan langsung memahami jawaban Bobince.
Incognito
1
Di mana saya dapat menemukan spek?
user985366
12

Ini PHP di mana string "0"itu falsy (false-when-used-in-boolean-context). Dalam JavaScript, semua string non-kosong adalah benar.

Kuncinya adalah bahwa ==melawan boolean tidak mengevaluasi dalam konteks boolean, itu dikonversi menjadi angka, dan dalam kasus string yang dilakukan dengan parsing sebagai desimal. Jadi Anda mendapatkan Nomor 0bukannya boolean kebenaran true.

Ini adalah desain bahasa yang sangat buruk dan itu salah satu alasan kami mencoba untuk tidak menggunakan ==operator yang malang . Gunakan ===sebagai gantinya.

bobince
sumber
7
// I usually do this:

x = "0" ;

if (!!+x) console.log('I am true');
else      console.log('I am false');

// Essentially converting string to integer and then boolean.
Thava
sumber
4

Kutipan Anda di sekitar 0membuatnya menjadi string, yang dievaluasi sebagai benar.

Hapus tanda kutip dan itu harus bekerja.

if (0) console.log("ha") 
Jason Gennaro
sumber
benar, bukan tentang bagaimana "membuatnya bekerja" tetapi pertanyaannya lebih seperti, "mengapa berperilaku seperti itu?"
nonopolaritas
1

Ekspresi "jika" menguji kebenaran, sedangkan tes ganda-sama untuk jenis-independen. Sebuah string selalu benar, seperti yang ditunjukkan orang lain di sini. Jika double-equal menguji kedua operan untuk kebenaran dan kemudian membandingkan hasilnya, maka Anda akan mendapatkan hasil yang Anda asumsikan secara intuitif, yaitu ("0" == true) === true. Seperti yang dikatakan Doug Crockford dalam JavaScript- nya yang luar biasa : Bagian-Bagian yang Baik , "aturan-aturan yang [== memaksa tipe operan-operannya] rumit dan tidak dapat dilupakan .... Kurangnya transitivitas mengkhawatirkan." Cukuplah untuk mengatakan bahwa salah satu operan adalah tipe-dipaksakan untuk mencocokkan yang lain, dan bahwa "0" akhirnya ditafsirkan sebagai angka nol,

Jollymorphic
sumber
1

== Operator kesetaraan mengevaluasi argumen setelah mengubahnya menjadi angka. Jadi string nol "0" dikonversi ke tipe data Number dan boolean false dikonversi ke Number 0. Jadi

"0" == false // true

Hal yang sama berlaku untuk `

false == "0" //true

=== Pemeriksaan kesetaraan ketat mengevaluasi argumen dengan tipe data asli

"0" === false // false, because "0" is a string and false is boolean

Hal yang sama berlaku untuk

false === "0" // false

Di

if("0") console.log("ha");

String "0" tidak membandingkan dengan argumen apa pun, dan string adalah nilai sebenarnya hingga atau kecuali jika dibandingkan dengan argumen apa pun. Persis seperti

if(true) console.log("ha");

Tapi

if (0) console.log("ha"); // empty console line, because 0 is false

`

Wisnu K. Panicker
sumber
1

Ini karena JavaScript menggunakan paksaan tipe dalam konteks Boolean dan kode Anda

if ("0") 

akan dipaksa untuk benar dalam konteks boolean.

Ada nilai-nilai kebenaran lain dalam Javascript yang akan dipaksa ke true dalam konteks boolean, dan dengan demikian mengeksekusi blok if adalah: -

if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)
Sachin
sumber