Ushbu boâlimning birinchi bobida biz prototipni oârnatish uchun zamonaviy usullar mavjudligini eslatib oâtdik.
__proto__ biroz eskirgan hisoblanadi (JavaScript standartining faqat brauzer qismida).
Zamonaviy usullar:
- Object.create(proto[, descriptors]) â
proto[[Prototype]]va ixtiyoriy xususiyat tavsiflovchilari sifatida boâsh obyektni yaratadi. - Object.getPrototypeOf(obj) â
objning[[Prototype]]ni qaytaradi. - Object.setPrototypeOf(obj, proto) â
objning[[Prototype]]niprotoga oârnatadi.
Ular __proto__ oârniga ishlatilishi kerak.
Masalan:
let animal = {
eats: true
};
// prototip sifatida animal bilan yangi obyekt yaratish
let rabbit = Object.create(animal);
alert(rabbit.eats); // true
alert(Object.getPrototypeOf(rabbit) === animal); // rabbit-ni prototipini olish
Object.setPrototypeOf(rabbit, {}); // rabbit prototipini {} ga o'zgartirish
Object.create ixtiyoriy ikkinchi argumentga ega: xususiyat tavsiflovchilari. U yerda yangi obyektga qoâshimcha xususiyatlarni taqdim etishimiz mumkin, masalan:
let animal = {
eats: true,
};
let rabbit = Object.create(animal, {
jumps: {
value: true,
},
});
alert(rabbit.jumps); // true
Deskriptorlar Xususiyat bayroqlari va tavsiflovchilar bobida tasvirlanganidek bir xil formatda boâladi.
Obyektni klonlashni for..in da nusxalash xususiyatlaridan koâra kuchliroq bajarish uchun Object.create dan foydalanishimiz mumkin:
// obj ning to'liq bir xil sayoz kloni
let clone = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
Ushbu chaqiruv obj ning barcha nusxalarini, shu jumladan, barcha xususiyatlarni: roâyxatga olinadigan va sanab boâlmaydigan maâlumotlarni, maâlumotlar xususiyatlarini va getter/setter-larni â hamma narsani va [[Prototype]] huquqini oladi.
Qisqa tarix
Agar biz [[Prototype]] ni boshqarishning barcha usullarini hisoblasak, juda koâp narsa bor! Buni bajarishning koâplab usullari mavjud!
Nega shunday?
Bu tarixiy sabablarga koâra.
- Konstruktor funktsiyasining
"prototype"xususiyati juda qadim zamonlardan beri ishlaydi. - Keyinchalik 2012 yilda:
Object.createstandartda paydo boâldi. Bu berilgan prototip bilan obyekt yaratishga imkon berdi, lekin uni olishga/oârnatishga imkon bermadi. Shunday qilib brauzerlar istalgan vaqtda prototipni olish/oârnatishga imkon beradigan nostandart__proto__kiruvchini qoâlladilar. - Keyinchalik 2015 yilda:
Object.setPrototypeOfvaObject.getPrototypeOfstandartga qoâshildi.__proto__hamma joyda amalga oshirildi, shuning uchun brauzerdan tashqari muhit uchun ixtiyoriy boâlgan standartning B ilovasiga yoâl oldi.
Hozirda bizda bu usullarning barchasi bizning ixtiyorimizda.
Nima uchun __proto__ funktsiyalar bilan almashtirildi? Bu qiziq savol, bizdan nima uchun __proto__ yomon ekanligini tushunishni talab qiladi. Javobni olish uchun oâqing.
[[Prototype]]ni qayta tiklamangTexnik jihatdan[[Prototype]]ni istalgan vaqtda olishimiz/oârnatishimiz mumkin. Ammo, odatda, biz uni obyektni yaratish vaqtida faqat bir marta oârnatamiz, keyin oâzgartirmaymiz:rabbit animal dan meros boâlib qoladi va bu oâzgarmaydi.
Va JavaScript interpretatori bunga juda moslashtirilgan. Object.setPrototypeOf yoki obj.__proto__= bilan prototipni âbajarilish paytidaâ oâzgartirish juda sekin operatsiya boâlib, u obyekt xususiyatlariga kirish operatsiyalari uchun ichki optimallashtirishni buzadi. Agar nima qilayotganingizni bilmasangiz yoki JavaScript-ning tezligi umuman siz uchun ahamiyatli boâlmasa, unda bundan qochib qutuling.
âJuda oddiyâ obyektlar
Maâlumki, obyektlar kalit/qiymat juftligini saqlash uchun assotsiativ massiv sifatida ishlatilishi mumkin.
â¦Ammo unda foydalanuvchi tomonidan taqdim etilgan kalitlarni saqlashga harakat qilsak (masalan, foydalanuvchi tomonidan kiritilgan lugâat), biz qiziqarli nosozlikni koârishimiz mumkin: "__proto__" dan tashqari barcha kalitlar yaxshi ishlaydi.
Misolni tekshiring:
let obj = {};
let key = prompt("Kalit nima??", "__proto__");
obj[key] = "some value";
alert(obj[key]); // [object Object], not "some value"!
Agar foydalanuvchi __proto__ ni yozsa, tayinlash eâtiborga olinmaydi!
Bu bizni ajablantirmasligi kerak. __proto__ xususiyati alohida: u obyekt yoki null boâlishi kerak, matn prototipga aylana olmaydi.
Ammo biz bunday xatti-harakatni amalga oshirishni xohlamaymiz, toâgârimi? Biz kalit/qiymat juftlarini saqlamoqchimiz, va "__proto__" nomli kalit toâgâri saqlanmadi. Demak bu xato!
Bu yerda yakunalar dahshatli emas. Ammo boshqa hollarda prototip haqiqatan ham oâzgartirilishi mumkin, shuning uchun ijro umuman kutilmagan yoâllar bilan notoâgâri ketishi mumkin.
Eng yomoni â odatda ishlab chiquvchilar bunday imkoniyat haqida umuman oâylamaydilar. Bu bunday xatolarni sezishni qiyinlashtiradi va hatto ularni zaif tomonlarga aylantiradi, ayniqsa JavaScript server tomonida ishlatilganda.
toString xususiyatiga kirishda kutilmagan holatlar yuz berishi mumkin â bu sukut boâyicha funktsiya va boshqa oârnatilgan xususiyatlar.
Muammodan qanday qochish kerak?
Birinchidan, biz Map dan foydalanishga oâtishimiz mumkin, keyin hamma narsa yaxshi.
Ammo Object ham bu yerda bizga yaxshi xizmat qilishi mumkin, chunki til yaratuvchilari bu muammo haqida juda oldin oâylab koârishgan.
__proto__ bu obyektning xususiyati emas, balki Object.prototype ga kiruvchi xususiyatdir:
Shunday qilib, agar obj.__proto__ oâqilgan yoki oârnatilgan boâlsa, mos keladigan getter/setter uning prototipidan chaqiriladi va u oladi/oârnatadi [[Prototype]].
Ushbu oâquv boâlimining boshida aytilganidek: __proto__ bu [[Prototype]] ga kirishning bir usuli, bu [[Prototype]] ning oâzi emas.
Endi biz obyektni assotsiativ massiv sifatida ishlatmoqchi boâlsak, buni biroz hiyla bilan amalga oshirishimiz mumkin:
let obj = Object.create(null);
let key = prompt("Kalit nima??", "__proto__");
obj[key] = "some value";
alert(obj[key]); // "some value"
Object.create(null) prototipsiz boâsh obyektni yaratadi ([[Prototype]] null):
Shunday qilib, __proto__ uchun getter/setter yoâq. Endi u odatdagi maâlumotlar xususiyati sifatida qayta ishlanadi, shuning uchun yuqoridagi misol toâgâri ishlaydi.
Bunday obyektni âjuda oddiyâ yoki âsof lugâat obyektlariâ deb atashimiz mumkin, chunki ular oddiy obyektga qaraganda oddiyroq {...}.
Salbiy tomoni shundaki, bunday obyektlarda oârnatilgan obyekt usullari mavjud emas, masalan, toString:
let obj = Object.create(null);
alert(obj); // Error (no toString)
â¦Ammo bu odatda assotsiativ massivlar uchun yaxshi.
Iltimos, eâtibor bering, obyekt bilan bogâliq usullarning aksariyati Object.something(...), masalan Object.keys(obj) â ular prototipda yoâq, shuning uchun ular bunday obyektlarda ishlashni davom ettiradi:
let chineseDictionary = Object.create(null);
chineseDictionary.hello = "ä½ å¥½";
chineseDictionary.bye = "åè§";
alert(Object.keys(chineseDictionary)); // hello,bye
Xulosa
Prototipni oârnatish va toâgâridan-toâgâri kirish uchun zamonaviy usullar:
- Object.create(proto[, descriptors]) â
[[Prototype]](nullboâlishi mumkin) sifatida berilganprotova ixtiyoriy xususiyatlar deskriptokrlari bilan boâsh obyektni yaratadi. - Object.getPrototypeOf(obj) â
objning[[Prototype]]ni qaytaradi (__proto__getter bilan bir xil). - Object.setPrototypeOf(obj, proto) â
objning[[Prototype]]niprotoga oârnatadi (__proto__oârnatuvchisi bilan bir xil).
Obyektga foydalanuvchi tomonidan yaratilgan kalitlarni qoâyishni xohlasak, oârnatilgan __proto__ getter/setter xavfli. Agar foydalanuvchi kalit sifatida __proto__ ni kiritishi mumkinligi sababli, umid qilamanki oson, ammo umuman kutilmagan oqibatlarga olib keladigan xato boâladi.
Shunday qilib, biz âjuda oddiyâ obyektni yaratish uchun Object.create(null) dan foydalanishingiz yoki __proto__ holda yoki Map moslamalarini qoâllashimiz mumkin.
Shuningdek, Object.create obyektni barcha tavsiflovchilar bilan sayoz nusxalashning oson usulini taqdim etadi:
let clone = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
We also made it clear that __proto__ is a getter/setter for [[Prototype]] and resides in Object.prototype, just like other methods.
- Object.keys(obj) / Object.values(obj) / Object.entries(obj) â sanab oâtiladigan oâz massiv nomlari/qiymatlari/kalit-qiymat juftliklari massivini qaytaradi.
- Object.getOwnPropertySymbols(obj) â barcha oâziga xos ramziy xususiyat nomlari massivini qaytaradi.
- Object.getOwnPropertyNames(obj) â oâzlarining barcha matn xususiyatlarining nomlarini qaytaradi.
- Reflect.ownKeys(obj) â barcha mulk nomlari massivini qaytaradi.
- obj.hasOwnProperty(key): agar
objningkeynomli oâziga xos (merosxoâr boâlmagan) xususiyati boâlsa, utrueni qaytaradi.
Shuningdek, biz __proto__ â bu [[Prototype]] uchun getter/setter ekanligini va boshqa usullar singari Object.prototype da joylashganligini ham aniqladik.
Biz Object.create(null) prototipisiz obyektni yaratishimiz mumkin. Bunday obyektlar âsof lugâatlarâ sifatida ishlatiladi, ularning kalitlari sifatida "__proto __" bilan bogâliq muammolar yoâq.
Obyekt xususiyatlarini qaytaradigan barcha usullar (Object.keys va boshqalar kabi) â âoâzâ xususiyatlarini qaytaradi. Agar biz merosxoârlarni xohlasak, unda for..in dan foydalanishimiz mumkin.
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â¦)