Prototip metodlari, __proto__siz obyektlar
__proto__ โ [[Prototype]] ni o'rnatish va o'qishning eng eski usuli, lekin u eskirgan (deprecated) hisoblanadi. Zamonaviy JavaScript prototiplar bilan ishlash uchun boshqa, ishonchliroq metodlarni taklif etadi. Bu darsda o'sha metodlar bilan tanishamiz.
Zamonaviy metodlar
Prototiplar bilan ishlashning uchta asosiy zamonaviy usuli bor:
Object.getPrototypeOf(obj)โobjning[[Prototype]]sini QAYTARADI (o'qiydi);Object.setPrototypeOf(obj, proto)โobjning[[Prototype]]siniprotoga O'RNATADI;Object.create(proto, [descriptors])โ berilganprotoni prototip qilib, YANGI bo'sh obyekt yaratadi (ixtiyoriy ravishda xossa deskriptorlari bilan).
__proto__ orqasidagi [[Prototype]] bilan bajaradi, lekin ishonchliroq va standart usulda. Zamonaviy kodda aynan shulardan foydalaning.Object.create bilan deskriptorlar
Object.create ning ikkinchi argumenti ixtiyoriy โ u xossa deskriptorlarini beradi. Bu bir chaqiruvda ham prototip, ham xossalarni o'rnatishga imkon beradi:
Object.create obyektni yuzaki (shallow) nusxalash uchun ham qulay โ u barcha xossalarni, jumladan getter/setter'larni va to'g'ri prototipni saqlab, aniq nusxa yaratadi:
Nima uchun __proto__ eskirgan?
__proto__ texnik jihatdan tilning yadrosida emas, brauzerlar uchun qo'shimcha standart (Annex B) sifatida ta'riflangan. Undan qochishning bir necha sabablari bor:
- U getter/setter bo'lgani uchun
Object.prototypeda yashaydi โ server (Node.js) muhitida boshqacha ishlashi mumkin; - Ishlash tezligi past โ
Object.setPrototypeOfyokiObject.createodatda samaraliroq; - Eng jiddiy muammo โ foydalanuvchidan kelgan kalitlar bilan ishlaganda xavfsizlik teshigi paydo bo'lishi mumkin.
__proto__ maxsus kalit sifatida g'alati xatti-harakat qilishi mumkin. Masalan, foydalanuvchi __proto__ nomli "kalit" kiritsa, oddiy tayinlash prototipni buzishga urinadi. Buni quyida ko'ramiz.Ko'rib turganingizdek, __proto__ kaliti oddiy ma'lumot kaliti kabi ishlamaydi โ u prototipni o'zgartirishga urinadi. Bu obyektni oddiy lug'at (map) sifatida ishlatganda jiddiy xatolarga olib keladi.
Object.create(null) โ "toza" obyekt
Yuqoridagi muammoning yechimi โ prototipi umuman yo'q obyekt yaratish. Object.create(null) prototipi null bo'lgan "toza" (chinakam bo'sh) obyekt yasaydi. Bunday obyektda __proto__ maxsus getter/setter'i yo'q, shuning uchun u oddiy kalit sifatida ishlaydi:
Bunday obyektlar ba'zan "very plain" yoki "pure dictionary" (toza lug'at) deb ataladi, chunki ular oddiy obyektlardan ham soddaroq โ ularda umuman meros olingan xossa yo'q.
Object.prototype dan meros olmagani uchun tayyor metodlarga (masalan, toString, hasOwnProperty) ega emas. Ammo Object.keys, Object.values kabi Object.* metodlari baribir ishlaydi, chunki ular obyektning o'zida emas, Object konstruktorida joylashgan.Object.create(null) yoki Map dan foydalaning. Ular __proto__ kabi maxsus kalitlar keltirib chiqaradigan xavfsizlik va mantiq muammolaridan xoli bo'ladi.Barcha xossalarni olish metodlari
Obyekt xossalarini olishning turli metodlari mavjud. Ularning barchasi obyektning O'Z xossalari ustida ishlaydi (prototipdagilar hisobga olinmaydi):
Object.keys(obj)/Object.values(obj)/Object.entries(obj)โ sanaladigan (enumerable) satr kalitlar/qiymatlar/juftliklar massivini qaytaradi;Object.getOwnPropertyNames(obj)โ barcha satr kalitlarni (sanalmaydiganlar ham) qaytaradi;Object.getOwnPropertySymbols(obj)โ barcha simvolli (symbol) kalitlarni qaytaradi;Reflect.ownKeys(obj)โ mutlaqo barcha kalitlarni qaytaradi.
Xulosa
- Zamonaviy kodda prototip bilan ishlash uchun
Object.create,Object.getPrototypeOf,Object.setPrototypeOfdan foydalaning; __proto__eskirgan โ tezlik va xavfsizlik sabab undan qoching;Object.create(proto, descriptors)obyektni aniq nusxalash uchun ham qulay;- Foydalanuvchidan kelgan kalitlar
__proto__orqali obyektni buzishi mumkin; Object.create(null)prototipsiz "toza" obyekt yaratadi โ u lug'at (dictionary) sifatida xavfsiz;Object.keys/values/entriesva boshqalar obyektning faqat o'z xossalari ustida ishlaydi.