Менчик "prototype"
JavaScript тилинин өзүндө кеңири колдонулат. Бардык орнотулган конструктор функциялары аны колдонот.
"prototype"
Биз адегенде майда-чүйдөсүнө чейин карап чыгабыз, анан аны орнотулган объекттерге жаңы функцияларды кошуу үчүн колдонобуз .
Объект.прототип
Келгиле, бош объект чыгаралы:
@A@let obj = {};
alert( obj ); // "[object Object]" ?@A@
Сапты түзгөн код кайда "[object Object]"
? Бул камтылган ыкма toString
, бирок ал кайда? obj
ал бош!
…Бирок, кыска белги obj = {}
менен бирдей, obj = new Object()
бул жерде Object
өзүнүн менчиги бар объекттер үчүн орнотулган конструктор функциясы бар prototype
, ал методу toString
жана башкалары бар чоң объектти билдирет.
Бул жерде эмне болот:
Объект чакырылганда new Object()
(же объект литерал аркылуу түзүлгөн {...}
), ал объекттин касиети биз мурунку бөлүмдө талкуулаган эрежелерге ылайык [[Prototype]]
коюлат :Object.prototype
Ошентип, качан чакырылса obj.toString()
, ыкма дан алынат Object.prototype
.
Биз муну сынай алабыз:
@A@let obj = {};
alert(obj.__proto__ === Object.prototype); // true
// obj.toString === obj.__proto__.toString === Object.prototype.toString@A@
Object.prototype
Жогорудагы прототип чынжырында мындан ары менчик жок экенине көңүл буруңуз [[Prototype]]
:
@A@alert(Object.prototype.__proto__); // null@A@
Башка орнотулган прототиптер
Башка орнотулган объекттер, мисалы Array
, Date
, Function
жана башкалар да өз ыкмаларын прототиптерде сакташат.
Мисалы, массивди түзүүдө [1, 2, 3]
массивдин конструктору ички түрдө колдонулат Array
. Ошентип, ал массивдин прототиби болуп калат Array.prototype
, аны өзүнүн ыкмалары менен камсыз кылат. Бул эстутумду натыйжалуу пайдаланууга мүмкүндүк берет.
Спецификацияга ылайык, орнотулган прототип иерархиясынын жогору жагында Object.prototype
. Ошондон улам кээде «бардыгы предметтен мурастайт» деп айтылат.
Бул жерде толугураак сүрөт (үч камтылган объект үчүн):
Келгиле, прототиптерди карап көрөлү:
@A@let arr = [1, 2, 3];
// наследует ли от Array.prototype?
alert( arr.__proto__ === Array.prototype ); // true
// затем наследует ли от Object.prototype?
alert( arr.__proto__.__proto__ === Object.prototype ); // true
// и null на вершине иерархии
alert( arr.__proto__.__proto__.__proto__ ); // null@A@
Прототиптердеги кээ бир методдор бири-бирине дал келиши мүмкүн, мисалы, алардын Array.prototype
өз ыкмасы бар toString
, ал массивдин элементтерин үтүр менен ажыратылган:
@A@let arr = [1, 2, 3]
alert(arr); // 1,2,3 <-- результат Array.prototype.toString@A@
Мурда көргөндөй, u Object.prototype
өзүнүн ыкмасына ээ toString
, бирок ал Array.prototype
прототип чынжырында жакыныраак болгондуктан, массивдердин варианты алынат:
Иштеп чыгуучунун консолу сыяктуу браузер куралдарында мурастоо чынжырын көрө аласыз ( console.dir
курган объекттер үчүн колдонуу керек болушу мүмкүн):
Башка орнотулган объекттер да ушундай эле түзүлүштө. Жада калса функциялар да орнотулган конструктор объекттери Function
жана алардын бардык ыкмалары ( call
/ apply
жана башкалар) Function.prototype
. Функциялардын да өз ыкмасы бар toString
.
@A@function f() {}
alert(f.__proto__ == Function.prototype); // true
alert(f.__proto__.__proto__ == Object.prototype); // true, наследует от Object@A@
Примитивдер
Эң кыйын бөлүгү саптар, сандар жана логикалык саптар менен болот.
Биз эстегендей, алар объектилер эмес. Бирок, эгерде биз алардын касиеттерине жетүүгө аракет кылсак, анда орнотулган конструкторлордун жардамы менен убактылуу орогуч объекти түзүлөт String
жана методдорун камсыздайт, анан жок болот.Number
Boolean
Бул объекттер биз үчүн көрүнбөй жаратылган жана көпчүлүк кыймылдаткычтар бул процессти оптималдаштыруу, бирок спецификация аны ушундай сүрөттөйт. String.prototype
Бул объекттердин ыкмалары, ошондой эле , Number.prototype
жана катары жеткиликтүү прототиптерде бар Boolean.prototype
.
null
жана undefined
орогуч объекттери жокӨзгөчө маанилери null
жана undefined
жалгыз турат. Алардын орогуч объекттери жок, ошондуктан методдор жана касиеттер аларга жеткиликтүү эмес. Алардын да тиешелүү прототиптери жок.
Inline прототиптерин өзгөртүү
Камтылган прототиптерди өзгөртүүгө болот. Мисалы, эгер сиз ыкманы -га кошсоңуз String.prototype
, ыкма бардык саптар үчүн жеткиликтүү болот:
@A@String.prototype.show = function() {
alert(this);
};
"BOOM!".show(); // BOOM!@A@
Иштеп чыгуу процессинде бизде жаңы орнотулган ыкмалар жөнүндө ойлорубуз жана аларды орнотулган прототиптерге кошуу азгырыгы болушу мүмкүн. Бул жаман идея.
Прототиптер глобалдуу, ошондуктан чыр-чатактар оңой эле пайда болушу мүмкүн. Эгерде эки китепкана бир методду кошсо String.prototype.show
, алардын бири экинчисинин ыкмасынын үстүнөн жазат.
Ошентип, жалпысынан, орнотулган прототиптерди өзгөртүү жаман идея болуп эсептелет.
Заманбап программалоодо, орнотулган прототиптерди өзгөртүүгө алгылыктуу болгон бир гана учур бар. Бул polyfills түзүү болуп саналат.
Polyfill бул JavaScript спецификациясында бар, бирок учурдагы JavaScript кыймылдаткычы тарабынан колдоого алынбаган ыкманы эмуляциялоону билдирген термин.
Андан кийин биз аны өзүбүз ишке ашырып, орнотулган прототипке кошо алабыз.
Мисалы:
@A@if (!String.prototype.repeat) { // Если такого метода нет
// добавляем его в прототип
String.prototype.repeat = function(n) {
// повторить строку n раз
// на самом деле код должен быть немного более сложным
// (полный алгоритм можно найти в спецификации)
// но даже неполный полифил зачастую достаточно хорош для использования
return new Array(n + 1).join(this);
};
}
alert( "La".repeat(3) ); // LaLaLa@A@
Прототиптерден карыз алуу
Бөлүмдө Decorators жана Чалууларды багыттоо, чалуу/колдонуу, биз карыз алуу ыкмалары жөнүндө сүйлөштүк.
Бул ыкманы бир объекттен алып, экинчисине көчүрүү.
Кээ бир орнотулган прототип ыкмалары көбүнчө карызга алынат.
Мисалы, массив сымал объектти (псевдо-массив) түзсөк, Array
бул объектке кээ бир методдорду көчүрө алабыз.
Мисал:
@A@let obj = {
0: "Hello",
1: "world!",
length: 2,
};
obj.join = Array.prototype.join;
alert( obj.join(',') ); // Hello,world!@A@
Бул иштейт, анткени ички ыкманын ички алгоритми join
индекстердин жана касиеттин тууралыгына гана кам көрөт length
, объект чындыгында массив экендигин текшербейт. Жана көптөгөн орнотулган ыкмалар бирдей иштейт.
obj.__proto__
Альтернативдик мүмкүнчүлүк катары орнотуу менен массивден мураска алабыз Array.prototype
, андыктан бардык ыкмалар Array
автоматтык түрдө жеткиликтүү болот obj
.
obj
Бирок, эгерде ал башка объекттен мураска калса, бул мүмкүн болбойт . Эсиңизде болсун, биз бир эле учурда бир гана объекттен мурас ала алабыз.
Карыз алуу ыкмалары зарыл болгон ар кандай объекттердин функционалдуулугун аралаштыруунун ийкемдүү жолу.
Бардыгы
- Бардык орнотулган объекттер бирдей үлгү боюнча:
- Методдор прототиптерде сакталат (
Array.prototype
,Object.prototype
,Date.prototype
ж.б.). - Объекттердин өздөрү гана маалыматтарды (массив элементтери, объекттин касиеттери, даталар) сакташат.
- Методдор прототиптерде сакталат (
- Примитивдер өз ыкмаларын орогуч объекттеринин прототиптеринде да сакташат:
Number.prototype
,String.prototype
,Boolean.prototype
. Болгону баалуулуктарundefined
жанаnull
орогуч объекттери жок. - Камтылган прототиптер жаңы ыкмалар менен өзгөртүлүшү же толукталышы мүмкүн. Бирок аларды өзгөртүү сунушталбайт. Жалгыз жүйөлүү себеп - JavaScript кыймылдаткычы тарабынан колдоого алынбаган стандарттан жаңы ыкманы кошуу.
Tasks
Прототиптеги бардык функцияларга defer(ms)
функцияларды ms
миллисекунддан кийин чакырган ыкманы кошуңуз.
Андан кийин, бул код иштеши керек:
@A@function f() {
alert("Hello!");
}
f.defer(1000); // выведет "Hello!" через 1 секунду@A@
Прототиптеги бардык функцияларга методду кошуңуз defer(ms)
, ал функциянын чакырылышын миллисекундга кечиктирген оромону кайтарат ms
.
Мисалы, ал төмөнкүдөй иштеши керек:
@A@function f(a, b) {
alert( a + b );
}
f.defer(1000)(1, 2); // выведет 3 через 1 секунду.@A@
Аргументтер баштапкы функцияга туура өтүшү керек экенин эске алыңыз.