Loading...

Прототип ыкмалары, __proto__ касиети жок объекттер

Прототип ыкмалары, __proto__ касиети жок объекттер

 

Бул бөлүмдүн биринчи бөлүмүндө биз прототиптер менен иштөөнүн заманбап ыкмалары бар экенин айттык.

Менчик __proto__эскирген жана стандарт боюнча браузерлер тарабынан гана колдоого алынышы керек.

Заманбап ыкмалары болуп төмөнкүлөр саналат:

Бул ыкмаларды ордуна колдонуу керек __proto__.

Мисалы:

@A@let animal = {
  eats: true
};

// создаём новый объект с прототипом animal
let rabbit = Object.create(animal);

alert(rabbit.eats); // true

alert(Object.getPrototypeOf(rabbit) === animal); // получаем прототип объекта rabbit

Object.setPrototypeOf(rabbit, {}); // заменяем прототип объекта rabbit на {}@A@

Анын Object.createкошумча экинчи аргументи бар: мулк дескрипторлору. Жаңы объектке төмөнкүдөй кошумча касиетти кошо алабыз:

@A@let animal = {
  eats: true
};

let rabbit = Object.create(animal, {
  jumps: {
    value: true
  }
});

alert(rabbit.jumps); // true@A@

Дескрипторлорду көрсөтүү форматы Flags жана касиеттин дескрипторлору бөлүмүндө сүрөттөлөт .

Object.createБиз ошондой эле циклдеги касиеттерди көчүрүүдөн күчтүүрөөк объектти клондоо үчүн колдоно алабыз for..in:

// клон obj c тем же прототипом (с поверхностным копированием свойств)
let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));

Мындай чалуу объекттин так көчүрмөсүн түзөт obj, анын ичинде бардык касиеттери: саналуучу жана саналбаган, касиеттерге алуучулар/жөндөөчүлөр - бардыгы туура касиетке ээ [[Prototype]].

Кыска окуя

Эгерде сиз прототипти башкаруунун бардык жолдорун санасаңыз, анда алар көп болот! Жана алардын көбү бир эле нерсени жасашат!

Эмнеге андай?

Тарыхый себептерден улам.

  • "prototype"Конструктор функциясынын касиети көптөн бери эле бар.
  • Кийинчерээк, 2012-жылы Object.create. Бул көрсөтүлгөн прототиби менен объекттерди түзүүгө мүмкүндүк берди, бирок аны орнотууга/алууга жол берген жок. Ал кезде браузерлер стандарттуу эмес аксессорду ишке ашырышкан __proto__, ал прототипти каалаган убакта орнотууга/чыгарып алууга мүмкүндүк берген.
  • Кийинчерээк, 2015-жылы алмаштыруучу аксессуар стандартка кошулган Object.setPrototypeOfObject.getPrototypeOf,ал __proto__стандарттын В тиркемесинде айтылган, ал браузерден тышкары чөйрөлөрдө колдоого алынбайт. Ошол эле учурда де-факто __proto__дагы эле бардык жерде колдоого алынат.

Натыйжада, азыр бизде прототиби менен иштөөнүн бардык жолдору бар.

Эмне үчүн __proto__ал функциялар менен алмаштырылган getPrototypeOf/setPrototypeOf? Жоопту билүү үчүн окуңуз.

[[Prototype]]Ылдамдык маанилүү болсо, учурдагы объекттерди өзгөртпөңүз

[[Prototype]]Техникалык жактан биз каалаган убакта орното/ала алабыз . Бирок, адатта, объектти түзүү учурунда прототипти бир гана жолу орнотобуз, андан кийин биз аны өзгөртпөйбүз: rabbitал дан мурастайт animalжана бул өзгөрбөйт.

Жана JavaScript кыймылдаткычтары бул үчүн жакшы оптималдаштырылган. Прототипти тез арада өзгөртүү Object.setPrototypeOfже obj.__proto__=объекттин касиетине кирүү операциялары үчүн ички оптималдаштырууну буза турган өтө жай операция. Андыктан эмне кылып жатканыңызды билмейинче же JavaScript ылдамдыгы сизди кызыктырбаса, андан качканыңыз жакшы.

"Эң жөнөкөй" объект

Белгилүү болгондой, объекттер ачкыч/баа жуптарын сактоо үчүн ассоциативдик массивдер катары колдонулушу мүмкүн.

…Бирок, эгерде биз колдонуучу тарабынан түзүлгөн ачкычтарды сактоого аракет кылсак (мисалы, колдонуучу киргизген сөздүктөр), биз кызыктуу мүчүлүштүктөрдү байкашыбыз мүмкүн: бардык баскычтар күтүлгөндөй иштейт, "__proto__".

Мисалга карагыла:

@A@let obj = {};

let key = prompt("What's the key?", "__proto__");
obj[key] = "some value";

alert(obj[key]); // [object Object], не "some value"!@A@

Колдонуучу кирсе __proto__, тапшырма этибарга алынбайт!

Жана бул бизди таң калтырбашы керек. Мүлк __proto__өзгөчө: ал объект же а болушу керек null, ал эми сап прототип боло албайт.

Бирок биз бул жүрүм-турумду ишке ашырууну көздөгөн эмеспиз , туурабы? Биз ачкыч/маани жуптарын сактагыбыз келет жана аталган ачкыч "__proto__"туура сакталган эмес. Демек, бул ката!

Бул конкреттүү мисалда кесепеттер анчалык деле коркунучтуу эмес, бирок биз объекттин баалуулуктарын ыйгарсак, анда прототибин чындап эле өзгөртүүгө болот. Натыйжада, андан ары аткаруу таптакыр күтүүсүз жол менен кетет.

Эң жаманы, иштеп чыгуучулар бул мүмкүнчүлүк жөнүндө такыр ойлонушпайт. Бул мындай каталарды кармоону кыйындатат же ал тургай, айрыкча серверде JavaScript колдонулганда, алсыздыктарга айланат.

toStringКүтүлбөгөн нерселер демейки боюнча функция болгон касиетти жана чындыгында орнотулган ыкмалар болгон башка касиеттерди дайындоодо да болушу мүмкүн .

Кантип көйгөйдөн качуу керек?

Биринчиден, биз коллекцияны колдонууга өтсөк болот Map, анан баары жакшы болот.

Бирок Objectал жакшы иштей алат, анткени тилди жаратуучулар маселени чечүү жолун көптөн бери ойлонуп келишкен.

Мүлк __proto__жөнөкөй эмес, төмөнкүдө аныкталган аксессуар болуп саналат Object.prototype

Ошентип, окуганда же орнотууда, obj.__proto__прототиптен тиешелүү алуучу/жөндөөчү деп аталат obj, жана бул касиетти орноткон/алат [[Prototype]].

Окутуучунун бул бөлүмүнүн башында айтылгандай, __proto__бул менчикке жетүүнүн жолу [[Prototype]], ал менчиктин өзү эмес [[Prototype]].

Эми, эгерде объектти ассоциативдик массив катары колдонгубуз келсе, анда биз муну бир аз куулук менен жасай алабыз:

@A@let obj = Object.create(null);

let key = prompt("What's the key?", "__proto__");
obj[key] = "some value";

alert(obj[key]); // "some value"@A@

Object.create(null)прототиби жок бош объектти түзөт ( [[Prototype]]эрк null):

Ошентип, . үчүн тукум кууган алуучу/жөндөөчү болбойт __proto__. Бул мүлк азыр кадимки менчик катары каралат жана жогорудагы мисал туура иштейт.

Биз мындай объектти "эң жөнөкөй" же "таза сөздүк объектиси" деп атасак болот, анткени ал кадимки объекттерден да жөнөкөй {...}.

Кемчилиги - мындай объекттерде орнотулган объекттик методдор болбойт, мисалы toString:

 
 
@A@let obj = Object.create(null);

alert(obj); // Ошибка (no toString)@A@

…Бирок бул адатта ассоциативдик массивдер үчүн жакшы.

Объекттерге байланышкан ыкмалардын көбү формада экенине көңүл буруңуз Object.something(...). Мисалы, Object.keys(obj). Мындай ыкмалар прототипте жок, ошондуктан алар мындай объекттер үчүн иштей беришет:

 
 
@A@let chineseDictionary = Object.create(null);
chineseDictionary.hello = "你好";
chineseDictionary.bye = "再见";

alert(Object.keys(chineseDictionary)); // hello,bye@A@

Бардыгы

орнотуунун заманбап ыкмалары жана прототиби түз жетүү болуп саналат:

  • Object.create(proto[, descriptors]) - (мүмкүн ) [[Prototype]]катары көрсөтүлгөн касиети жана кошумча касиеттин дескрипторлору менен бош объектти түзөт .protonull
  • Object.getPrototypeOf(obj) - [[Prototype]]объекттин касиетин кайтарат obj(алуучу сыяктуу __proto__).
  • Object.setPrototypeOf(obj, proto)[[Prototype]] - объекттин касиетин (setter менен эле obj) орнотот .proto__proto__

Эгерде биз объектте колдонуучу тарабынан түзүлгөн__proto__ ачкычтарды колдонгубуз келсе, орнотулган алуу/жөндөөчү коопсуз эмес. Жок дегенде, себеби колдонуучу ачкыч катары киргизе алат, бул катага алып келиши мүмкүн. Эгер бактылуу болсоңуз, кесепеттери жумшак болот, бирок, жалпысынан алганда, алар күтүүсүз болот."__proto__"

Object.create(null)Ошентип, биз "жөнөкөй" объектти түзүү үчүн колдоно алабыз , же Map.

Мындан тышкары, Object.createал бизге бардык дескрипторлор менен объекттин тайыз көчүрмөсүн түзүүнүн оңой жолун берет:

let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));

Биз ошондой эле __proto__мүлк үчүн алуучу/жөндөөчү экенин айкын көрдүк жана ал башка ыкмалар сыяктуу эле [[Prototype]]жайгашкан .Object.prototype

Биз прототиптери жок объекттерди түзө алабыз Object.create(null). Мындай объекттерди "таза сөздүктөр" катары колдонсо болот, аларда сапты "__proto__"ачкыч катары колдонууда көйгөй жок.

Көбүрөөк ыкмалар:

Объекттин касиеттерин кайтарган бардык ыкмалар (мисалы, Object.keysбашкалар) "өздүк" касиеттерин кайтарат. Эгерде биз да мураска алгыбыз келсе, анда биз колдоно алабыз for..in.

Tasks

маанилүүлүгү: 5

Ар кандай жуптарды сактоо үчүн dictionaryтүзүлгөн объект бар .Object.create(null)ключ/значение

dictionary.toString()Ачкычтардын үтүр менен бөлүнгөн тизмесин кайтара турган ыкманы кошуңуз . Объектти цикл менен итерациялоодо сиздики toStringчыгарылбашы керек for..in.

Бул кандай иштеши керек:

@A@let dictionary = Object.create(null);

// ваш код, который добавляет метод dictionary.toString

// добавляем немного данных
dictionary.apple = "Apple";
dictionary.__proto__ = "test"; // здесь __proto__ -- это обычный ключ

// только apple и __proto__ выведены в цикле
for(let key in dictionary) {
  alert(key); // "apple", затем "__proto__"
}

// ваш метод toString в действии
alert(dictionary); // "apple,__proto__"@A@
чечим
маанилүүлүгү: 5

Келгиле, жаңы объект түзөлү rabbit:

@A@function Rabbit(name) {
  this.name = name;
}
Rabbit.prototype.sayHi = function() {
  alert(this.name);
};

let rabbit = new Rabbit("Rabbit");@A@

Бул чалуулардын бардыгы бирдей эле нерсени жасайбы же жокпу?

@A@rabbit.sayHi();
Rabbit.prototype.sayHi();
Object.getPrototypeOf(rabbit).sayHi();
rabbit.__proto__.sayHi();@A@