Mengapa baris ini valid dalam javascript?
var a = 0[0];
Setelah itu, a
is undefined
.
javascript
Michael M.
sumber
sumber
true[0]
atau""[0]
"0"
dari sebuahnew Number(0)
objek.0[0]
mengembalikan nilai0["toString"]
Itu luar biasa, terima kasih telah menunjukkannya.Jawaban:
Ketika Anda melakukannya
0[0]
, juru bahasa JS akan mengubah yang pertama0
menjadiNumber
objek dan kemudian mencoba mengakses[0]
properti objek ituundefined
.Tidak ada kesalahan sintaks karena sintaks akses properti
0[0]
diperbolehkan oleh tata bahasa dalam konteks ini. Struktur ini (menggunakan istilah dalam tata bahasa Javascript) adalahNumericLiteral[NumericLiteral]
.Bagian yang relevan dari tata bahasa dari bagian A.3 dari spesifikasi ES5 ECMAScript adalah ini:
Jadi, seseorang dapat mengikuti grammer melalui perkembangan ini:
Dan, demikian
Expression
pula pada akhirnya bisaNumericLiteral
jadi setelah mengikuti tata bahasa, kita melihat bahwa ini diperbolehkan:Yang berarti itu
0[0]
adalah bagian tata bahasa yang diizinkan dan karenanya tidak ada SyntaxError.Kemudian, pada waktu proses Anda diizinkan untuk membaca properti yang tidak ada (hanya akan dibaca sebagai
undefined
) selama sumber yang Anda baca adalah objek atau memiliki konversi implisit ke objek. Dan, literal numerik memang memiliki konversi implisit menjadi objek (objek Angka).Ini adalah salah satu fitur Javascript yang sering tidak dikenal. Jenis
Number
,Boolean
danString
dalam Javascript biasanya disimpan secara internal sebagai primitif (bukan objek yang lengkap). Ini adalah representasi penyimpanan yang kompak dan tidak dapat diubah (mungkin dilakukan dengan cara ini untuk efisiensi implementasi). Namun, Javascript ingin Anda dapat memperlakukan objek primitif ini seperti objek dengan properti dan metode. Jadi, jika Anda mencoba mengakses properti atau metode yang tidak didukung secara langsung pada primitif, maka Javascript akan memaksa primitif untuk sementara menjadi tipe objek yang sesuai dengan nilai yang ditetapkan ke nilai primitif.Saat Anda menggunakan sintaks mirip objek pada primitif seperti
0[0]
, interpreter mengenali ini sebagai akses properti pada primitif. Responsnya terhadap hal ini adalah dengan mengambil0
primitif numerik pertama dan memaksanya menjadi objek full-blownNumber
yang kemudian dapat mengakses[0]
properti. Dalam kasus khusus ini,[0]
properti pada objek Angkaundefined
itulah sebabnya itulah nilai yang Anda dapatkan0[0]
.Berikut adalah artikel tentang konversi otomatis dari primitif menjadi objek untuk tujuan menangani properti:
Kehidupan Rahasia Primitif Javascript
Berikut adalah bagian yang relevan dari spesifikasi ECMAScript 5.1:
9.10 CheckObjectCoercible
Melempar TypeError jika nilainya adalah
undefined
ataunull
, jika tidak, dikembalikantrue
.11.2.1 Pengakses Properti
Bagian operasi untuk pertanyaan ini adalah langkah # 5 di atas.
8.7.1 GetValue (V)
Ini menjelaskan bagaimana ketika nilai yang diakses adalah referensi properti, ia memanggil
ToObject(base)
untuk mendapatkan versi objek dari primitif apa pun.9.9 ToObject
Ini menjelaskan bagaimana
Boolean
,Number
danString
primitif dikonversi ke bentuk objek dengan properti internal [[PrimitiveValue]] disetel sesuai.Sebagai tes yang menarik, jika kodenya seperti ini:
Itu masih tidak akan memunculkan SyntaxError pada waktu parse karena ini secara teknis adalah sintaks yang legal, tetapi itu akan memunculkan TypeError saat runtime ketika Anda menjalankan kode karena ketika logika Pengakses Properti di atas diterapkan ke nilai
x
, itu akan memanggilCheckObjectCoercible(x)
atau memanggilToObject(x)
yang mana akan menampilkan TypeError jikax
adalahnull
atauundefined
.sumber
0[1,2]
juga valid, apa artinya? (Saya memperbarui pertanyaan)null
atauundefined
sama sekali baik-baik saja, bahkan jika properti itu tidak ada.0[2]
1,2
tetapi mengembalikan 2.Seperti kebanyakan bahasa pemrograman, JS menggunakan tata bahasa untuk mengurai kode Anda dan mengubahnya menjadi bentuk yang dapat dieksekusi. Jika tidak ada aturan dalam tata bahasa yang dapat diterapkan ke potongan kode tertentu, SyntaxError akan muncul. Jika tidak, kode dianggap valid, tidak peduli apakah masuk akal atau tidak.
Bagian yang relevan dari tata bahasa JS adalah
Karena
0[0]
sesuai dengan aturan ini, ini dianggap sebagai ekspresi yang valid . Apakah itu benar (misalnya tidak menimbulkan kesalahan pada waktu proses) adalah cerita lain, tapi ya itu benar. Beginilah cara JS mengevaluasi ekspresi sepertisomeLiteral[someExpression]
:someExpression
(yang dapat menjadi kompleks sewenang-wenang)Number
, string =>String
dll)get property
operasi pada hasil (2) dengan hasil nama properti (1)Jadi
0[0]
diartikan sebagaiBerikut adalah contoh ekspresi yang valid , tetapi salah :
Ini diuraikan dengan baik, tetapi pada waktu proses, penafsir gagal pada langkah 2 (karena
null
tidak dapat diubah menjadi objek) dan memunculkan kesalahan waktu proses.sumber
var x = null; var a = x[0];
tidak menghasilkan kesalahan sintaks, tetapi memunculkan TypeError saat runtime.0[0]
mengembalikan nilai alih-alih tidak ditentukanAda situasi di mana Anda dapat secara valid memasukkan angka dalam Javascript:
Meskipun tidak segera jelas mengapa Anda ingin melakukan ini, berlangganan dalam Javascript sama dengan menggunakan notasi titik (meskipun notasi titik membatasi Anda untuk menggunakan pengenal sebagai kunci).
sumber
(0).toString
(tanpa memanggil fungsi). Ini adalah properti dari tipe angka.0
properti diakses dan karena itu tidak ada,undefined
yang lebih tepat seperti yang dijelaskan dalam jfriend00.0[0]
akan kembali tidak terdefinisi. Kemungkinan akan terjadi, tetapi tidak harus demikianSaya hanya ingin mencatat bahwa sintaks yang valid ini sama sekali tidak unik untuk Javascript. Sebagian besar bahasa akan memiliki kesalahan waktu proses atau kesalahan jenis, tetapi itu tidak sama dengan kesalahan sintaks. Javascript memilih untuk mengembalikan tak terdefinisi dalam banyak situasi di mana bahasa lain mungkin memunculkan pengecualian, termasuk saat memasukkan objek yang tidak memiliki properti dari nama yang diberikan.
Sintaks tidak mengetahui jenis ekspresi (bahkan ekspresi sederhana seperti literal numerik), dan memungkinkan Anda menerapkan operator apa pun ke ekspresi apa pun. Misalnya, mencoba untuk subskrip
undefined
ataunull
menyebabkanTypeError
di Javascript. Ini bukan kesalahan sintaks - jika ini tidak pernah dijalankan (berada di sisi yang salah dari pernyataan-if), itu tidak akan menimbulkan masalah, sedangkan kesalahan sintaks secara definisi selalu tertangkap pada waktu kompilasi (eval, Fungsi, dll. , semuanya dihitung sebagai kompilasi).sumber
Karena itu sintaks yang valid, dan bahkan kode yang valid untuk diinterpretasikan. Anda dapat mencoba mengakses properti apa pun dari objek apa pun (dan dalam kasus ini 0 akan dilemparkan ke objek Angka), dan ini akan memberi Anda nilai jika ada, jika tidak, tidak ditentukan. Namun, mencoba mengakses properti undefined tidak berhasil, jadi 0 [0] [0] akan menghasilkan error runtime. Ini masih akan diklasifikasikan sebagai sintaks yang valid. Ada perbedaan antara sintaks yang valid dan apa yang tidak menyebabkan kesalahan waktu proses / waktu kompilasi.
sumber
Tidak hanya sintaksnya valid, hasilnya tidak harus seperti itu
undefined
di sebagian besar, jika tidak semua kasus waras itu akan terjadi. JS adalah salah satu bahasa berorientasi objek paling murni. Kebanyakan yang disebut bahasa OO adalah berorientasi kelas, dalam arti bahwa Anda tidak dapat mengubah bentuk (terikat pada kelas) dari objek setelah dibuat, hanya status objek. Di JS Anda dapat mengubah status serta bentuk objek dan ini Anda lakukan lebih sering daripada yang Anda pikirkan. Kemampuan ini membuat kode yang agak tidak jelas, jika Anda menyalahgunakannya. Angka tidak dapat diubah, jadi Anda tidak dapat mengubah objek itu sendiri, baik itu status maupun bentuknya sehingga Anda dapat melakukannyayang merupakan ekspresi penugasan valid yang mengembalikan 1 tetapi tidak benar-benar menetapkan apa pun, Angka
0
tidak dapat diubah. Yang dengan sendirinya agak aneh. Anda dapat memiliki ekspresi assingment yang valid dan benar (dapat dijalankan), yang tidak menetapkan apa pun (*). Namun tipe angka adalah objek yang bisa berubah sehingga Anda bisa mengubah tipe, dan perubahan akan menuruni rantai prototipe.tentu saja ini jauh dari kategori penggunaan yang waras tetapi bahasanya ditentukan untuk memungkinkan hal ini karena dalam skenario lain, memperluas kemampuan objek sebenarnya sangat masuk akal. Begitulah cara plugin jQuery menghubungkan ke objek jQuery untuk memberikan contoh.
(*) Ini benar-benar menetapkan nilai 1 ke properti objek, namun tidak ada cara Anda dapat mereferensikan objek (transcient) itu dan dengan demikian akan dikumpulkan di nexx GC pass
sumber
Dalam JavaScript, semuanya adalah objek, jadi ketika interpreter menguraikannya, ia memperlakukan 0 sebagai objek dan mencoba mengembalikan 0 sebagai properti. Hal yang sama terjadi saat Anda mencoba mengakses elemen ke 0 dari true atau "" (string kosong).
Meskipun Anda menyetel 0 [0] = 1, ini akan menyetel properti dan nilainya dalam memori, tetapi saat Anda mengakses 0, ia diperlakukan sebagai angka (Jangan bingung antara memperlakukan sebagai Objek dan angka di sini.)
sumber