Dalam Javascript setiap objek memiliki metode valueOf () dan toString (). Saya akan berpikir bahwa metode toString () dipanggil setiap kali konversi string dipanggil, tetapi tampaknya itu dikalahkan oleh valueOf ().
Misalnya kode
var x = {toString: function() {return "foo"; },
valueOf: function() {return 42; }};
window.console.log ("x="+x);
window.console.log ("x="+x.toString());
akan mencetak
x=42
x=foo
Ini menurut saya terbalik .. jika x adalah bilangan kompleks, misalnya, saya ingin valueOf () memberi saya besarnya, tetapi setiap kali saya ingin mengonversi ke string, saya menginginkan sesuatu seperti "a + bi". Dan saya tidak ingin memanggil toString () secara eksplisit dalam konteks yang menyiratkan string.
Apakah begini adanya?
javascript
otak macet
sumber
sumber
window.console.log (x);
ataualert (x);
?alert(x)
ditampilkanfoo
danwindow.console.log(x)
ditampilkanObject { toString: x.toString(), valueOf: x.valueOf() }
.Jawaban:
Alasan mengapa ("x =" + x) memberikan "x = nilai" dan bukan "x = tostring" adalah sebagai berikut. Saat mengevaluasi "+", pertama-tama javascript mengumpulkan nilai primitif dari operan, lalu memutuskan apakah penambahan atau penggabungan harus diterapkan, berdasarkan jenis setiap primitif.
Jadi, menurut Anda inilah cara kerjanya
dan inilah yang sebenarnya terjadi
Artinya, toString diterapkan ke hasil valueOf, bukan ke objek asli Anda.
Untuk referensi lebih lanjut, lihat bagian 11.6.1 Operator Penambahan (+) di Spesifikasi Bahasa ECMAScript.
* Ketika dipanggil dalam konteks string, ToPrimitive memang memanggil toString, tetapi ini tidak terjadi di sini, karena '+' tidak memberlakukan konteks tipe apa pun.
sumber
Ini sedikit lebih detail, sebelum saya mendapatkan jawabannya:
The
toString
fungsi tidak "palsu" olehvalueOf
pada umumnya. Standar ECMAScript sebenarnya menjawab pertanyaan ini dengan cukup baik. Setiap objek memiliki[[DefaultValue]]
properti, yang dihitung sesuai permintaan. Saat meminta properti ini, penerjemah juga memberikan "petunjuk" untuk nilai seperti apa yang diharapkannya. Jika petunjuknyaString
, makatoString
digunakan sebelumnyavalueOf
. Tapi, jika petunjuknyaNumber
, makavalueOf
akan digunakan dulu. Perhatikan bahwa jika hanya ada satu, atau mengembalikan non-primitif, biasanya akan memanggil yang lain sebagai pilihan kedua.The
+
Operator selalu menyediakan petunjuk yangNumber
, bahkan jika operan pertama adalah nilai string. Meskipun memintax
untuk perusahaanNumber
representasi, karena operan pertama mengembalikan sebuah string dari[[DefaultValue]]
, itu tidak penggabungan string.Jika Anda ingin menjamin yang
toString
dipanggil untuk penggabungan string, gunakan array dan.join("")
metode.(ActionScript 3.0 sedikit mengubah perilaku
+
, namun. Jika salah satu operand adalah aString
, itu akan memperlakukannya sebagai operator penggabungan string dan menggunakan petunjukString
ketika dipanggil[[DefaultValue]]
. Jadi, di AS3, contoh ini menghasilkan "foo, x = foo, foo = x, foo1, 43, x = foo ".)sumber
valueOf
atautoString
mengembalikan non-primitif, mereka diabaikan. Jika tidak ada, atau tidak ada yang mengembalikan primitif, maka aTypeError
dilemparkan.[[DefaultValue]](no-hint)
, yang setara dengan[[DefaultValue]](number)
.("" + new Date(0)) === new Date(0).toString()
. Objek Tanggal sepertinya selalu mengembalikantoString()
nilainya saat ditambahkan ke sesuatu.TLDR
Paksaan tipe, atau konversi tipe implisit, memungkinkan pengetikan lemah dan digunakan di seluruh JavaScript. Kebanyakan operator (dengan pengecualian penting dari operator kesetaraan yang ketat
===
dan!==
), dan operasi pemeriksaan nilai (misalnyaif(value)...
), akan memaksa nilai yang diberikan kepada mereka, jika jenis nilai tersebut tidak segera kompatibel dengan operasi.Mekanisme tepat yang digunakan untuk memaksa nilai bergantung pada ekspresi yang dievaluasi. Dalam pertanyaan, operator penjumlahan sedang digunakan.
Operator penjumlahan pertama-tama akan memastikan kedua operan adalah primitif, yang, dalam hal ini, melibatkan pemanggilan
valueOf
metode. ThetoString
Metode ini tidak disebut dalam hal ini karena ditimpavalueOf
metode pada objekx
mengembalikan nilai primitif.Kemudian, karena salah satu operan yang dimaksud adalah string, maka kedua operan tersebut akan diubah menjadi string. Proses ini menggunakan abstrak, operasi internal
ToString
(catatan: huruf besar), dan berbeda daritoString
metode pada objek (atau rantai prototipe).Akhirnya, string yang dihasilkan digabungkan.
Detail
Pada prototipe setiap objek fungsi konstruktor yang sesuai dengan setiap jenis bahasa dalam JavaScript (mis. Number, BigInt, String, Boolean, Symbol, dan Object), ada dua metode:
valueOf
dantoString
.Tujuannya
valueOf
adalah untuk mengambil nilai primitif yang terkait dengan suatu objek (jika ada). Jika sebuah objek tidak memiliki nilai primitif yang mendasari, maka objek tersebut dikembalikan begitu saja.Jika
valueOf
dipanggil terhadap primitif, maka primitif tersebut otomatis dimasukkan ke dalam kotak dengan cara normal, dan nilai primitif yang mendasarinya dikembalikan. Perhatikan bahwa untuk string, nilai primitif yang mendasari (yaitu nilai yang dikembalikan olehvalueOf
) adalah representasi string itu sendiri.Kode berikut menunjukkan bahwa
valueOf
metode mengembalikan nilai primitif yang mendasari dari objek pembungkus, dan ini menunjukkan bagaimana contoh objek yang tidak dimodifikasi yang tidak sesuai dengan primitif, tidak memiliki nilai primitif untuk dikembalikan, jadi mereka hanya mengembalikan dirinya sendiri.Tujuan dari
toString
, di sisi lain, adalah mengembalikan representasi string dari suatu objek.Sebagai contoh:
Untuk sebagian besar operasi, JavaScript akan secara diam-diam mencoba mengonversi satu atau lebih operan ke jenis yang diperlukan. Perilaku ini dipilih untuk membuat JavaScript lebih mudah digunakan. JavaScript awalnya tidak memiliki pengecualian , dan ini mungkin juga berperan dalam keputusan desain ini. Jenis konversi jenis implisit ini disebut pemaksaan jenis, dan ini adalah dasar dari sistem jenis JavaScript yang longgar (lemah). Aturan rumit di balik perilaku ini dimaksudkan untuk memindahkan kerumitan typecasting ke dalam bahasa itu sendiri, dan keluar dari kode Anda.
Selama proses koersif, ada dua mode konversi yang dapat terjadi:
Number()
,Boolean()
,String()
Dll)Konversi Menjadi Primitif
Ketika mencoba untuk mengubah tipe non-primitif menjadi primitif untuk dioperasikan, operasi abstrak
ToPrimitive
dipanggil dengan "petunjuk" opsional dari 'nomor', atau 'string'. Jika petunjuk dihilangkan, petunjuk default adalah 'nomor' (kecuali jika@@toPrimitive
metode telah diganti). Jika petunjuknya adalah 'string', makatoString
dicoba dulu, danvalueOf
kedua jikatoString
tidak mengembalikan primitif. Lain, sebaliknya. Petunjuknya tergantung pada operasi yang meminta konversi.Operator tambahan tidak memberikan petunjuk, jadi
valueOf
dicoba dulu. Operator pengurangan memberikan petunjuk 'angka', jadivalueOf
coba dulu. Satu-satunya situasi yang dapat saya temukan dalam spesifikasi di mana petunjuknya adalah 'string' adalah:Object#toString
ToPropertyKey
, yang mengubah argumen menjadi nilai yang dapat digunakan sebagai kunci propertiKonversi Jenis Langsung
Setiap operator memiliki aturannya sendiri untuk menyelesaikan operasinya. Operator tambahan pertama-tama akan digunakan
ToPrimitive
untuk memastikan setiap operand adalah primitif; kemudian, jika salah satu operand adalah string, maka dengan sengaja akan memanggil operasi abstrakToString
pada setiap operan, untuk menyampaikan perilaku penggabungan string yang kita harapkan dengan string. Jika, setelahToPrimitive
langkah, kedua operan bukan string, maka dilakukan penjumlahan aritmatika.Tidak seperti penjumlahan, operator pengurangan tidak memiliki perilaku kelebihan beban, sehingga akan memanggil
toNumeric
setiap operan yang telah mengonversinya terlebih dahulu menjadi penggunaan primitifToPrimitive
.Begitu:
Perhatikan bahwa
Date
objek intrinsik itu unik, karena itu adalah satu-satunya intrinsik yang mengganti@@toPrimitive
metode default , di mana petunjuk default dianggap sebagai 'string' (bukan 'number'). Alasan untuk memiliki ini, adalah agarDate
instance diterjemahkan ke string yang dapat dibaca secara default, bukan nilai numeriknya, demi kenyamanan programmer. Anda dapat menimpa objek@@toPrimitive
Anda sendiri menggunakanSymbol.toPrimitive
.Grid berikut menunjukkan hasil pemaksaan untuk operator persamaan abstrak (
==
) ( sumber ):Lihat juga .
sumber