Obyektlar obj1 + obj2
qo’shilganda, obj1 - obj2
ayirilganda yoki alert(obj)
yordamida ekranga chiqarilganda nima bo’ladi?
Obyektlarda konvertatsiya qiladigan maxsus usullar mavjud.
"type-convertions" maqolasi topilmadi bobida biz ibtidoiylarning raqamli, matn va mantiqiy konvertatsiya qilish qoidalarini ko’rdik. Ammo biz obyektlar uchun bo’sh joy qoldirdik. Endi usullar va belgilar to’g’risida bilganimizdan so’ng, bo’shlikni to’ldirish vaqti keldi.
Obyektlar uchun mantiqiy konvertatsiya mavjud emas, chunki barcha obyektlar mantiqiy kontekstda true
. Shunday qilib, faqat matn va raqamli konvertatsiyalar mavjud.
Raqamli konvertatsiya obyektlarni ayirganda yoki matematik funktsiyalarni qo’llaganimizda sodir bo’ladi. Masalan, Date
obtektlari (Sana va vaqt bobida ko’rib chiqilishi kerak) ayirilishi mumkin va date1 - date2
natijasi ikki sana o’rtasidagi vaqt farqidir.
Matn konvertatsiyasiga kelsak, bu odatda alert(obj)
kabi obyektni chiqarganimizda va shunga o’xshash kontekstda sodir bo’ladi.
ToPrimitive
Obyekt ibtidoiy zarur bo’lgan kontekstda, masalan, alert
yoki matematik operatsiyalarda ishlatilsa, u ToPrimitive
algoritmi (spetsifikatsiya yordamida ibtidoiy qiymatga aylantiriladi).
Bu algoritm bizga maxsus obyekt usuli yordamida konvertatsiyani sozlash imkonini beradi.
Spetsifikatsiyada tavsiflangan uchta turdagi o’zgartirishlar (“uchta hintlar”) mavjud:
"string"
-
Amaliyot matni kutganda, obyektni matnga aylantirish uchun, masalan,
alert
:// chiqish alert(obj); // obyektni xususiyat kaliti sifatida ishlatish anotherObj[obj] = 123;
"number"
-
Amaliyot matematikaga o’xshash raqamni konvertatsiya qilish uchun raqamni kutganda:
// aniq konvertatsiya let num = Number(obj); // matematika (unar plyusdan tashqari) let n = +obj; // unar plyus let delta = date1 - date2; // kamroq/katta taqqoslash let greater = user1 > user2;
"default"
-
Kamdan kam hollarda operator qanday turni kutishini “aniq bilmasa” paydo bo’ladi.
Masalan, unar plyus
+
ikkala matnlar (ularni birlashtiradi) va raqamlar (ularni qo’shadi) bilan ishlashi mumkin, shuning uchun ham matnlar, ham raqamlar bilan ishlaydi. Yoki obyektni==
yordamida matn, raqam yoki belgi bilan taqqoslaganda.// binar plus let total = car1 + car2; // obj == matn/raqam/belgi if (user == 1) { ... };
Katta / kichik operator
<>
ikkala satr va raqamlar bilan ham ishlashi mumkin. Shunga qaramay, u “default” emas, balki “number” ishoradan foydalanadi. Bu tarixiy sabablarga ko’ra.Amalda, bitta holatdan tashqari barcha tilning ichida o’rnatilgan obyektlar (
Date
obyekti, biz keyinroq organib olamiz)"default"
konvertatsiyasini"number"
bilan bir xil tarzda amalga oshiradi. Va ehtimol biz ham shunday qilishimiz kerak.
Iltimos, diqqat qiling – faqat uchta ishora mavjud. Bu juda oddiy. Hech qanday “mantiqiy” ishora yo’q (barcha obyektlar mantiqiy turdagi qiymatda true
) yoki boshqa narsalar. Agar biz "default"
va "number"
ga bir xil munosabatda bo’lsak, aksariyat ichki o’rnatilganlar singari, faqat ikkita konvertatsiya mavjud.
Konvertatsiyani amalga oshirish uchun JavaScript uchta obyekt usulini topishga va ularni chaqirishga harakat qiladi:
- Agar usul mavjud bo’lsa,
obj[Symbol.toPrimitive](hint)
ni chaqiring, - Aks holda, agar ishora
"string"
bo’lsa- mavjud bo’lsa ham,
obj.toString()
vaobj.valueOf()
ni sinab ko’ring.
- mavjud bo’lsa ham,
- Aks holda, agar ishora
"number"
yoki"default"
bo’lsa- mavjud bo’lsa ham,
obj.toString()
vaobj.valueOf()
ni sinab ko’ring.
- mavjud bo’lsa ham,
Symbol.toPrimitive
Birinchi usuldan boshlaylik. Konvertatsiya usulini quyidagicha nomlash uchun ishlatilishi kerak bo’lgan Symbol.toPrimitive
belgisi mavjud:
obj[Symbol.toPrimitive] = function (hint) {
// ibtidoiy qiymatni qaytaring
// hint = "string", "number", "default" dan biri
};
Masalan, user
obyekti buni amalga oshiradi:
let user = {
name: "John",
money: 1000,
[Symbol.toPrimitive](hint) {
alert(`hint: ${hint}`);
return hint == "string" ? `{name: "${this.name}"}` : this.money;
},
};
// konvertatsiya demo:
alert(user); // hint: string -> {name: "John"}
alert(+user); // hint: number -> 1000
alert(user + 500); // hint: default -> 1500
Koddan ko’rinib turibdiki, user
konvertatsiyaga qarab o’z-o’zini tavsiflovchi matnga yoki pul miqdoriga aylanadi. user[Symbol.toPrimitive]
yagona usuli barcha konvertatsiyaga ishlaydi.
toString/valueOf
toString
va valueOf
usullari qadimgi davrlardan kelib chiqqan. Ular belgilar emas (belgilar ilgari mavjud bo’lmagan), aksincha “muntazam” matn nomli usullar. Ular konvertatsiyani amalga oshirishning muqobil “eski uslubi” ni taqdim etadi.
Agar Symbol.toPrimitive
bo’lmasa, JavaScript ularni topishga harakat qiladi va quyidagi tartibda sinab ko’radi:
toString -> valueOf
“string” ishora uchun.valueOf -> toString
aks holda.
Masalan, bu erda user
yuqoridagi kabi toString
va valueOf
kombinatsiyasidan foydalangan holda ishlaydi:
let user = {
name: "John",
money: 1000,
// hint="string" uchun
toString() {
return `{name: "${this.name}"}`;
},
// hint="number" yoki "default" uchun
valueOf() {
return this.money;
},
};
alert(user); // toString -> {name: "John"}
alert(+user); // valueOf -> 1000
alert(user + 500); // valueOf -> 1500
Ko’pincha biz barcha ibtidoiy konversiyalarni boshqarish uchun bitta “hamma narsani ushlab turadigan” joyni xohlaymiz. Bunday holda biz faqat toString
‑ni amalga oshirishimiz mumkin:
let user = {
name: "John",
toString() {
return this.name;
},
};
alert(user); // toString -> John
alert(user + 500); // toString -> John500
Symbol.toPrimitive
va valueOf
bo’lmasa, toString
barcha ibtidoiy konversiyalarni boshqaradi.
ToPrimitive va ToString/ToNumber
Barcha ibtidoiy konversiya usullari haqida bilish kerak bo’lgan narsa shundaki, ular “ishora qilingan” ibtidoiyni qaytarishligi shart.
toString()
aniq bir matni qaytarishi yoki Symbol.toPrimitive
usuli “raqam” ishora uchun aniq raqamni qaytarishi shart emas.
Faqatgina majburiy narsa: ushbu usullar ibtidoiylarni qaytarishi kerak.
Konvertatsiyani boshlagan operatsiya ushbu ibtidoiylarni oladi va keyinchalik u bilan ishlashni davom ettiradi, agar kerak bo’lsa, keyingi konvertatsiyalarni qo’llaydi.
Masalan:
-
Matematik operatsiyalar (binar plyusdan tashqari)
ToNumber
konvertatsiyasini bajaradi:let obj = { toString() { // toString boshqa usullar bo'lmasa, barcha o'zgarishlarni ko'rib chiqadi return "2"; }, }; alert(obj * 2); // 4, ToPrimitive "2" ni qaytaradi, keyin u 2 ga aylanadi
-
Binar plyus ibtidoiylarni tekshiradi – agar u matn bo’lsa, u holda birikma hosil qiladi, aks holda u
ToNumber
ni bajaradi va raqamlar bilan ishlaydi.String misoli:
let obj = { toString() { return "2"; }, }; alert(obj + 2); // 22 (ToPrimitive matn => birlashtirish qaytarildi)
Number misoli:
let obj = { toString() { return true; }, }; alert(obj + 2); // 3 (ToPrimitive mantiqiy turdagi qiymat qaytarildi, matn bo'lmasa => ToNumber)
Tarixiy sabablarga ko’ra toString
yoki valueOf
usullari ibtidoiylarni qaytarishi kerak: agar ulardan birortasi obyektni qaytarsa, unda xato bo’lmaydi, ammo bu obyekt e’tiborga olinmaydi (masalan, uslub mavjud bo’lmagandak).
Aksincha, Symbol.toPrimitive
ibtidoiylarni qaytarishi shart, aks holda xato bo’ladi.
Xulosa
Obyektni ibtidoiy konvertatsiya qilish ko’plab o’rnatilgan funktsiyalar va operatorlar tomonidan avtomatik ravishda chaqiriladi, ular qiymat sifatida ibtidoiylarni kutadilar.
Uning 3 turi (ishoralari) mavjud:
"string"
(alert
va boshqa matn konvertatsiyalari uchun)"number"
(matematika uchun)"default"
(ba’zi operatorlar uchun)
Spetsifikatsiyada qaysi operator qaysi maslahatni ishlatishi aniq tasvirlangan. “Nima kutishni bilmaydigan” va "default"
ishorasidan foydalanadigan operatorlar juda kam. Odatda tilning ichida o’rnatilgan obyektlar uchun "default"
ishora "number"
bilan bir xil tarzda ko’rib chiqiladi, shuning uchun amalda oxirgi ikkitasi ko’pincha birlashtiriladi.
Konvertatsiya qilish algoritmi:
- Agar usul mavjud bo’lsa,
obj[Symbol.toPrimitive](hint)
ni chaqiring, - Aks holda, agar ishora
"string"
bo’lsa- mavjud bo’lsa ham,
obj.toString()
vaobj.valueOf()
ni sinab ko’ring.
- mavjud bo’lsa ham,
- Aks holda, agar ishora
"number"
yoki"default"
bo’lsa- mavjud bo’lsa ham,
obj.toString()
vaobj.valueOf()
ni sinab ko’ring.
- mavjud bo’lsa ham,
Amalda, faqat obj.toString()
ni amalga oshirish juda keng tarqalgan, barcha turdagi transformatsiyalar uchun “universal” usul bo’lib, obyektning “o’qiladigan” ko’rinishini qaytaradigan barcha konvertatsiyalar uchun, koddagi nosozliklarni maqsadida amalga oshirish kifoya.
Izohlar
<code>
yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>
yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)