Javascript динамично променящи се обекти. JavaScript обекти чрез пример. Нека повторим нашите имоти

Задачата :

1. Има три обекта (три коли): първа_кола, втора_Автомобилаи трета_Автомобила.

2. Всеки един от обектите (коли)има набор от свойства и съответните им стойности (характеристики на превозното средство).

3. Помислете за един от обектите:

вар първа_автомобила = (
марка: "VAZ",
/* производител */
модел: 2106,
/ * модел * /
година: 1980 г.,
/* година на издаване */
цвят: "бежов",
/* Цвят */
пътници: 5,
/ * брой пътници * /
конвертируемо: фалшиво,
/ * кабриолет * /
пробег: 80000
/* пробег */
}

Имоти направии цвятимат низови стойности;

Имоти модел, година, пътниции пробег- числови стойности;

Имот кабриолетприема булева стойност.

Трябва да направите следното:

Напишете функция, която проверява колата по два параметъра (година на производство и пробег)и връща булева стойност вярноили фалшиво.

Подробности:

1. Функцията има един параметър кола, в качеството на който получава един от 3-те обекта. Например колата, обсъдена по-горе първа_кола.

2. Функцията трябва да работи с всеки подобен обект.

Функция за проверка на обект - вярно или невярно

Коментари за решението:

  • И така, имаме три обекта (три коли), всеки от които може да бъде анализиран с помощта на функцията добра_Кола.
  • Функция добра_Колаима един параметър кола, което може да бъде всеки от обектите (коли): първа_кола, втора_Автомобилаили трета_Автомобила: функция добра_Автомобил (кола) .
  • В функциите на тялото добра_Колае съставено условие, според което:

    Ако стойността на имота годинаобект колапо-малко от 2000 (с други думи: ако годината на производство на автомобила е по-малка от 2000 г.)след това функцията се връща фалшиво;

    В противен случай, ако стойността на имота пробегобект колаповече от 50 000 (ако пробегът на автомобила е повече от 50 000)след това функцията се връща фалшиво;

    В противен случай функцията се връща вярно.

  • След това извикваме функцията и указваме обекта като параметър трета_Автомобила(трета кола)който успешно преминава теста. Резултатът от функцията се съхранява в променлива резултат:
    var резултат = добра_Автомобила (трета_Кола); .
  • Променлива резултатпоказва се на екрана;
  • Други два обекта (кола)няма да отговарят на изискванията на условието.

Оптимизиране на вашия код

Нека продължим работа с обекти в javascript.

И така, горната функция при проверка на обекти (коли)дава като резултат вярноили фалшиво (истина или лъжа).

Възможно е леко да се подобри качеството на възприемане на решението на разглеждания проблем, тоест вместо вярноили фалшивопоказване на произволен текст. За да направим това, ще създадем условие за анализиране на резултата.

Условно решение за резултат - Резултат ...

Условието за анализ на резултата е съставено, както следва.

  • Изразяване ако (резултат)е съкратена форма на изразяване
    ако (резултат == вярно) .
  • Ако резултатът от функцията добра_Кола истина е вярно, след което показваме фразата: „Имаш добра кола: 2012 година на производство, с пробег 15000 км.“, къде

    2012 и 15000 са стойности на имоти годинаи пробегобект трета_Автомобила.

  • Ако условието за проверка на резултата ще върне фалшива стойност фалшиво, тогава ще видим: "Няма да говорим за колата ти ....". Тоест въпросният обект (автомобил)неуспешна проверка.

Оптимизация на кода - По-нататък - Добавяне на функция

Но това не е всичко. Разгледайте отблизо кодовия фрагмент за извикване на функцията и анализиране на резултата:

/ * Извикване на функцията и анализиране на резултата * /
var резултат = добра_Автомобила ( трета_Автомобила );

ако (резултат) (
document.write ("Имаш хубава кола:" + трета_Автомобила .година + "година на производство, с пробег" + трета_Автомобила .пробег + "км.");
}
друго (
document.write ("Да не говорим за колата ти...");
}

Ето обекта трета_Автомобила (трета кола)се посочва три пъти:

  • За първи път извикване на функция добра_Колатой е посочен като негов параметър: добра_Кола (трета_Кола) .
  • И тогава се появява още два пъти, когато се позоваваме на него, за да посочим неговите свойства: трета_Автомобила.годинаи трети_Автомобил.пробег .

Това не ми хареса, защото при анализ на друг обект (кола)ще имаме и неговото име посочете три пъти!!!

За да постигнете еднократна индикация на анализирания обект, имате нужда и от резултата от функцията добра_Колаи анализ на този резултат (тоест цялото) добавяне към друга функция.

Решение с помощта на още една функция - Резултат ...

Имаш добра кола: 2012 г., с 15 000 км пробег.

Посещението на уеб ресурс е специфичен URI в адресната лента на браузъра. Посетителят посочва адреса на страницата и той се анализира от браузъра на елементи от дървото на DOM - Document Object Model. Всяка връзка на тази страница казва на браузъра да анализира друга страница и да изгради друго дърво от обекти.

Браузърът позволява на посетителя да се върне назад или напред през верига от страници, които вече са били прегледани в текущата сесия.

Всъщност действията на потребителите се движат между системи от обекти, образувани в процеса на посещение на страници. Всяка страница е свое собствено DOM дърво и в допълнение, JavaScript обектите са обекти на синтаксиса на самия език и персонализирани описания.

DOM: зареждане, актуализиране и промяна

Има три основни опции, които формират обектите на страницата с уеб ресурс, както на ниво DOM, така и на самия JavaScript език, който изпълнява конструкциите за създаване на променливи и въз основа на описанията, направени от разработчика:

  • зареждане - посетителят дойде на страницата на сайта;
  • актуализация - посетител (бутон на браузъра или Ctrl-F5);
  • промяна на елемент на страница, например (AJAX, скрипт, събитие, ...).

И трите процеса са коренно различни, но е особено важно да се разграничат характеристиките на първите два. Трудно е да се попречи на посетител да опресни страницата - това е неизкоренена пристрастяване на посетителите, която разработчикът трябва да има предвид.

Навигацията из страницата и отвъд нея трябва да се състои изключително във функционалността на самата страница, а не в историята на посещенията на браузъра и функциите на нейните бутони. Много сайтове декларират това важно изискване, но посетителите традиционно го нарушават.

Промяната на страницата без презареждане на нивото на отделния й елемент (например AJAX) е често срещано решение за динамични страници. По правило това се използва за навигация през елементите на страницата, промяна на нейните обекти, контрол на диалога с посетителя.

Основни JavaScript обекти

JavaScript е обектно-базиран. Почти всички езикови променливи са обекти. Разработчикът може да формулира свои собствени описания на обекти, използвайки различни синтаксиси.

Всичко, което не е "низ", "число", true, false, null или undefined, е обект. В рамките на синтаксиса на езика това може да се пренебрегне, като се разбират от обекти само DOM елементи и собствените описания на JavaScript обекта.Фундаменталната структура на езика в повечето случаи за разработчика няма значителна практическа стойност.

Например математическите функции са представени от обекта Math. Това е удобно в рамките на концепцията за езика, но за разработчика това е просто удобен синтаксис за използване на необходимия арсенал от математически операции.

Важно е да работите правилно с DOM и правилно да описвате собствените си обекти. Синтаксисът на обектната функция на JavaScript и изразите за прилагането им е форма за писане на логиката на необходимия алгоритъм.

Низове, масиви и обекти

Всички JavaScript обекти се основават на правилото "свойство" = "стойност" и концепцията за асоциативен масив. Най-просто, обектният JavaScript е колекция от двойки свойство = стойност. В този случай "стойността" не винаги може да бъде число и свойството не винаги се записва без кавички.

Именуването на свойствата не трябва да се прекалява. В идеалния случай, когато имената на свойства съдържат само латински знаци, отговарят на изискванията за именуване на променливи и не са ключови (включително запазени) думи на езика.

Не се очаква подреждане на свойствата, но когато създавате или инициализирате асоциативен масив, е напълно приемливо да знаете как са подредени неговите елементи. Не се препоръчва използването на това обстоятелство, но е възможно да се има предвид.

Инициализирането на масив от свойства означава едновременно:

  • създаване на масив;
  • създаване на обект.

В конкретен контекст на приложението можете да разглеждате JavaScript обект - като асоциативен масив и другаде в алгоритъма - като обект, да му присвоите необходимите методи, да промените стойностите на неговите елементи.

Тъй като имената и стойностите на свойствата трябва да бъдат посочени в низов формат, когато се създават или променят, се препоръчва да използвате нотация с малки букви и кавички.

Достъп до свойствата на обекта

Можете да получите и промените стойностите на свойствата на обекта с конструкцията Object.keys: JavaScript формира масив от всички свойства на обекта. Когато обектите се създават динамично, тази конструкция е много удобна, защото автоматично генерира списък с всички свойства в обекта.

В този пример описанието на двата масива е направено по различен начин. При употреба и двата масива са еквивалентни, тъй като съдържат свойства със същото име и техните стойности. Цикълът преглежда всички свойства на втория масив и образува низ от всички стойности.

Подобен ефект може да се постигне с нотация с точки или скоби:

  • x1_Obj .NameLast;
  • x1_Obj [„NameFirst“].

И двете конструкции са валидни и дават желания резултат. В дадения пример, когато се посочва масив чрез фигурни скоби "()", може да се направи грешка под формата на символа "," в края на изброяването (маркирано в примера с червен кръг). Браузърите обикновено игнорират допълнителния символ в изброяването, но е най-добре да не го правят.

Премахване на свойствата на обекта

Тъй като обектът е асоциативен масив, операцията Обектът за изтриване на JavaScript се изпълнява на нивото на текущия обект (с наследяване - има значение) и се преглежда в колекцията от свойства на този обект.

В контекста на дадения пример можете да използвате следните конструкции:

  • изтрийте x1_Obj .NameLast;
  • изтрийте x2_Obj ["NameFirst"];

Първата конструкция премахва втория елемент от първия обект, втората конструкция премахва първия елемент на втория обект. Операторът delete не работи върху свойствата на прототипа и връща false, ако свойството не може да бъде изтрито.

Свойства и методи на обекти

Синтаксисът на свойствата и функциите (методи) на JavaScript обекти е подобен на общите канони на синтаксиса и семантиката на езика. Всъщност е точно обратното.

Свойствата и методите на обекта са вариант на описание на информация и действия, разрешени с нея чрез обектно-ориентираната парадигма на JavaScript.

Този пример описва обекта x3_Obj, който има само две свойства: item и pos. След това методът hello () беше добавен като функция. В резултат на това интерпретацията на това описание в контекста на стойностите на свойствата, стойностите на обекти на JavaScript ще се извърши, както е показано в прозореца с резултати, тоест ще постави тялото на функцията (1) като стойност.

Когато свойството Hello () се извика директно, то се интерпретира като метод (функция) и резултатът (2) ще бъде изпълнението на кода на този метод.

Ключовата дума this върху обект

За да се ориентира в пространството на свойствата на обект, разработчикът може да използва ключовата дума this и да препрати чрез нея към свойствата, които описва, за да получи или промени техните стойности.

Това е само началото на описването на обект само с тяло на конструктор. Този пример описва обект на бисквитка. Обектът се инициализира в момента, в който страницата се зареди с конструкцията:

  • var oCookie = нови scCookies (cOwnerCode);
  • oCookie .Init ();

В този пример cOwnerCode е уникален идентификатор на посетителя. Ако не, тогава в конструктора на обекта oCookie ще бъде генериран нов код. Няма значение какво има предвид разработчикът на този обект с оторизация на посетителя, важно е как тук се използва ключовата дума this, за да опишат методите на обекта и да ги извика от други методи на обекта:

  • това .GetCookie = функция (cName) (...);
  • това .SetCookie = функция (cName, cValue) (...).

Ето как се описват методите на обекта за четене на бисквитка по нейното име и записване на стойността на бисквитка с конкретно име.

  • този .GetCookie ("собственик");
  • този .SetCookie ("cOwner", собственик);

Така че те се използват, ако в резултат на първата конструкция стойността няма да бъде представена, тогава втората конструкция я задава.

Пример за обект на бисквитка

Може да се обсъжда обективната и обектно-ориентираната парадигма на език, работещ в среда на браузър. Това е интересно, но реалността е практика, а не теория. Обслужването на DOM на страница, предоставянето на инструментариум за манипулиране на обекти и навигация в обективни системи е силна страна. JavaScript.

В обектно-ориентираната практика е важно нещо друго. Работата с бисквитки в почти всички уеб ресурси е в реда на нещата. Прилагането на това в обектен формат е страхотна идея. В този контекст инициализацията на обекта се случва в момента на отваряне на страницата: страницата се зарежда = обектът cookie съществува и е прочел всичко, а това, което не е било - създадено.

В процеса на работа със страницата посетителят извършва определени действия и браузърът трябва да промени или създаде бисквитки. Има два обектни метода (описани по-горе), които правят това.

Всъщност бисквитката се появява веднага след като браузърът изгради DOM и добави нова функционалност към обектната система на JavaScript: прочетете и създайте (променете) бисквитката.

В този прост пример той се разглежда като процедура за създаване на реални обекти, които имат изключително свои собствени свойства и функционалност (методи). Всеки обект върши своята работа и не участва в общия алгоритъм, не променя данните на други обекти или общото пространство от имена.

С този подход разработчикът гарантира създаването на система от уникални обекти, достатъчни за описване и поддържане на решавания проблем.

Събития на страница и обект

Важен елемент от функционирането на DOM и JavaScript: обект събитие "s - ви позволява да получите информация за събитие в неговия манипулатор. На почти всеки елемент от страницата може да бъде присвоен собствен манипулатор за едно или повече събития.

Всъщност разработчикът на JavaScript не създава едно голямо "парче" код, а много описания на функции, обекти, структури от данни и присвоява манипулатори на събития към конкретни елементи на страницата.

Обектно събитие е информация за събитието, което е причинило манипулатора и способността на този манипулатор да извърши адекватен отговор на това събитие. Всяко събитие се различава не само по името и мястото на възникване, но и по много други параметри.

По-специално, събитията на клавиатурата са един набор от параметри, събитията при мишката са съвсем различен диапазон от данни, а отговорът на сървъра чрез AJAX е изцяло планиран от самия разработчик.

Във всеки конкретен случай картината на събитията, които могат да възникнат на страницата, се трансформира в набор от включени манипулатори; извън предвидените опции за обработка на конкретен набор от събития, страницата не предприема никакви действия.

Създаване и работа на обект

Браузърът "трансформира" URI, адреса на уеб ресурса, посочен от посетителя, в DOM дърво - системата от обекти на страниците на този уеб ресурс. Когато посетителят се движи през връзките на страницата, браузърът се придвижва до съответните дървета на други страници.

Това обстоятелство позволява на разработчика да изгради своя собствена система от обекти като основа на уеб ресурс, който адекватно реагира на поведението на посетителя. Ако отделим общата функционалност, например:

  • работа с бисквитки;
  • получаване/предаване на данни (AJAX);
  • изскачащи съвети;
  • вътрешни съобщения (чат на сайта);
  • други задачи;

веднъж създадени, обективните системи могат да се използват за разработване на други сайтове. Това е значително предимство на обектния подход пред обичайното използване на JavaScript като език на браузъра, който осигурява функционирането на страницата и реакцията на събития.

Обектите са цялостни компоненти, които могат да бъдат стилизирани като отделни файлове и да се използват по-късно. Характерна особеност на този подход е възможността за обратна връзка, когато актуализиран, подобрен обект може да се използва в предишна разработка, като автоматично се актуализира функционалността му, без да се модифицира сайта.

В тази статия искам да говоря възможно най-пълно и последователно за това какво представлява един обект в JavaScript, какви са неговите възможности, какви връзки могат да бъдат изградени между обектите и какви методи на „родно“ наследяване следват от това, как всичко това се отразява изпълнение и какво прави всичко :)

В статията НЯМА да се каже нито дума за: емулация на традиционната парадигма клас-обект, синтактична захар, опаковки и рамки.

Сложността на материала ще се увеличава от началото до края на статията, така че за професионалистите първите части може да изглеждат скучни и тривиални, но по-нататък ще бъде много по-интересно :)

Обекти в JavaScript

Много статии съдържат фразата „В JavaScript всичко е обект“. Технически това не е съвсем вярно, но прави правилното впечатление на начинаещите :)

Наистина, много от езика е обект и дори това, което не е обект, може да има някои от неговите възможности.

Важно е да се разбере, че думата "обект" се използва тук не в смисъла на "обект от определен клас". Обектът в JavaScript е преди всичко просто колекция от свойства (ако е по-лесно за някого, можете да го наречете асоциативен масив или списък), състоящ се от двойки ключ-стойност. Освен това ключът може да бъде само низ (дори за елементи на масив), но стойността може да бъде всеки тип данни, изброени по-долу.

Така че има 6 в JavaScript основни видовеДанните са Undefined (означаващи без стойност), Null, Boolean (булев), String (низ), Number (число) и Object (обект).
Още повече, че първите 5 са примитивентипове данни, но Object не е. Освен това може условно да се предположи, че типът Object има "подтипове": масив (Array), функция (Function), регулярен израз (RegExp) и други.
Това е малко опростено описание, но на практика обикновено е достатъчно.

В допълнение, примитивните типове String, Number и Boolean са свързани по някакъв начин с непримитивните „подтипове“ на Object: String, Number и Boolean, съответно.
Това означава, че низът "Здравей, свят", например, може да бъде създаден както като примитивна стойност, така и като обект от тип String.
Накратко, това се прави, за да може програмистът да използва методи и свойства, когато работи с примитивни стойности, сякаш са обекти. Можете да прочетете повече за това в съответния раздел на тази статия.

Работете по препратка

Връзката е средство за достъп до обект под различни имена. Работата с всякакви обекти се извършва изключително чрез препратка.
Нека демонстрираме това с пример:
тест = функция () (предупреждение ("Здравей!")) // Създайте функция (предупреждение ("Здравей!")) (И функцията, както си спомняме, е пълноправен обект) и направете тестовата променлива препратка към нея
тест_връзка = тест; // test_link сега също се отнася до нашата функция
тест (); // Здравейте!
тест_връзка (); // Здравейте!


Както виждаме, и първата връзка, и втората дават един и същ резултат.
Необходимо е да разберем, че нямаме функция с име test и че променливата на теста не е някакъв вид "главна" или "главна" връзка, а "test_link" е второстепенна.

Нашата функция, както всеки друг обект, е просто област в паметта и всички препратки към тази област са абсолютно еквивалентни. Освен това обектът може изобщо да няма препратки - в този случай той се нарича анонимен и може да се използва само веднага след създаването (например, предадено на функция), в противен случай ще бъде невъзможно да се осъществи достъп до него и скоро той ще бъде унищожен от колектора за боклук (събиране на боклук), което изтрива обекти без препратки.

Нека видим защо е толкова важно да разберем това:

тест = (реклама: "някакъв текст") // Създаване на обект със свойство prop
тест_връзка = тест; // Създайте друга връзка към този обект

Сигнал (test.prop); // някакъв текст

// Промяна на свойството на обекта
test_link.prop = "нов текст";

Сигнал (test.prop); // нов текст
предупреждение (test_link.prop); // нов текст
/ * Може да се каже, че имотът се е променил тук-там - но не е така.
Обектът е един. Така свойството се е променило веднъж в него и връзките просто продължават да сочат къде сочат. * /

// Добавяне на ново свойство и премахване на старото
test.new_prop = "здравей";
изтрийте test.prop;

Сигнал (test_link.prop); // undefined - това свойство вече не съществува
предупреждение (test_link.new_prop);

// Премахване на връзката
тест за изтриване;
предупреждение (test.new_prop);
/ * В този момент скриптът ще изведе грешка, тъй като testът вече не съществува и test.new_prop не съществува още повече * /
предупреждение (test_link.new_prop); // Здравейте
/ * но тук всичко е наред, защото не изтрихме самия обект, а само връзка към него. Сега нашият обект е посочен от една връзка test_link * /

// Създаване на нов обект
тест = тест_връзка; // Първо, създайте отново тестовата връзка
test_link = (prop: "някакъв текст") // И тук е новият обект

Сигнал (test_link.prop); // някакъв текст
предупреждение (test.prop); // неопределено
/ * Създаването на нов обект прекъсва връзката и сега test и test_link сочат към различни обекти.
Всъщност това е равносилно на премахване на test_link и повторното му създаване, но вече насочване към друг обект * /
предупреждение (test.new_prop); // здравей - сега тестът съдържа връзка към първия ни обект


* Този изходен код беше подчертан с Source Code Highlighter.

Това поведение на обектите често повдига много въпроси за начинаещите разработчици, така че се надявам този текст да внесе известна яснота. Ако искаме да създадем наистина ново, независимо копие на обекта, а не връзка, тогава единственият начин да направим това е да създадем нов обект и да копираме необходимите свойства там.

Също така си струва да се отбележи, че работата с обекти чрез препратка, в допълнение към гореспоменатите забавни ефекти, осигурява и значителна икономия на памет, което е важно, когато един обект се използва широко на различни места в програмата.

Примитивни ценности

Както споменах по-горе, типовете данни String и Number могат да бъдат както обекти, така и примитивни стойности.
obj = нов низ ("здравей"); // Създаване на низ като обект
просто = "здравей"; // Създаване на примитивна стойност

Сигнал (obj); // Здравейте
предупреждение (просто); // здравейте - засега всичко е предвидимо

Сигнал (дължина на обекта); // 6 - обект от тип String има свойство за дължина, което съхранява дължината на низа
предупреждение (simple.length); // 6
/ * Въпреки че простото не е обект, ние можем да получим достъп до същия набор от свойства като String обект. Това е доста удобно * /

Obj.prop = "текст";
simple.prop = "текст";

Сигнал (obj.prop); // текст - тъй като obj е обикновен обект, тогава лесно можем да му дадем още едно свойство
предупреждение (simple.prop); // undefined - но простото не е обект и това число няма да работи за нас

* Този изходен код беше подчертан с Source Code Highlighter.


Същото важи и за Number и Boolean (е, освен факта, че те нямат свойство за дължина, но има редица други прекрасни свойства).
Използването на низове и числа като обекти няма практическа полза. Примитивните стойности са по-удобни за работа, но в същото време запазват цялата необходима функционалност. Въпреки това, за пълнота е необходимо да се разбере този механизъм.

Не бъркайте използването на примитивни стойности с използването на литерали - например, независимо дали създаваме масив като "test = new Array ()" или като "test =", резултатът все още ще бъде същият обект . Няма да получим никакви примитивни стойности.

Създаване и използване на обекти

Така че, за разлика от езиците, където се прилага парадигмата клас-обект, не е необходимо първо да създаваме клас, а след това да създаваме обект на класа. Можем веднага да създадем обект, което ще направим в следния пример:
тест = (
simple_property: "Здравейте",
свойство_обект: (
потребител_1: "Петя",
потребител_2: "Вася"
},
function_property: функция (потребител) (
предупреждение (това .simple_property + "," + това .object_property);
}
}

Test.function_property ("user_1"); // Здравей, Петя.

* Този изходен код беше подчертан с Source Code Highlighter.


Пред нас е тестовият обект, който има 3 свойства, чиито имена, надявам се, говорят сами за себе си. Това, което ни интересува най-много в него, е свойството function_property, което съдържа функцията. Такава функция може да се нарече метод на обект.

Нашата функция използва тази ключова дума два пъти, която е указател (т.е. препратка) към обекта, от който се извиква функцията. По този начин, this.simple_property = test.simple_property = "Здравей", и this.object_property = test.object_property = "Питър".

Трябва ясно да се разбере, че това винаги се отнася до обекта, от който е извикана функцията, а не до обекта, към който принадлежи. Въпреки че това са един и същи обект в този пример, това не винаги е така.

test.function_property ("user_1"); // Здравей, Петя.

Тест2 = нов обект (); // Друга форма за създаване на нов обект, подобна на test2 = ()

Test.function_property.call (test2, "user_1"); // грешка
/ * Методът на извикване ви позволява да извикате функция от името на друг обект. В този случай ние извикваме метода function_property на тестовия обект и това сочи вече не към тестовия обект, а към обекта test2. И тъй като той няма свойството object_property, тогава когато се опитате да получите this.object_property, скриптът ще даде грешка * /

// опитайте се да поправите ситуацията
test2.simple_property = "Добър ден";
test2.object_property = test.object_property; // В този случай ще използваме посочване на обекта чрез препратка, за да не дублираме кода

Test.function_property.call (test2, "user_1"); // Добър ден, Петя.


* Този изходен код беше подчертан с Source Code Highlighter.

От примера също трябва да е ясно, че няма ясни стъпки за създаване и използване на обект. Обектът може да бъде модифициран по всякакъв начин по всяко време - преди, след и дори по време на употреба. Това също е важна разлика от "традиционното" ООП.

Конструктор

В примера по-горе създадохме 2 обекта, които имат някои прилики. Присъстваха както свойствата simple_property, така и object_property. Очевидно при писане на реален код често възниква задачата за създаване на идентични или просто подобни обекти. И разбира се, не е нужно да създаваме всеки такъв обект ръчно.

На помощ ще ни се притече конструктор. Конструкторът в JavaScript не е част от клас (защото няма класове), а само функция. Най-често срещаната функция.

направи_ме = функция (_name) (
предупреждение („Бях пуснат“);
това .name = _name;

}


/ * Да видим какво става тук. Преводачът вижда новия оператор и проверява какво е вдясно от него. Защото make_me е функция и може да се използва като конструктор, след което в паметта се създава нов обект и се изпълнява функцията make_me и това сочи към този нов обект. След това към този обект се добавя свойството name, на което се присвоява стойността от аргумента _name и метода show_name. Също така (не знам в кой точно момент, но няма значение) детската променлива започва да сочи към нашия нов, току-що роден обект * /

Сигнал (child.name); //Вася
child.show_name (); //Вася


child2.show_name (); //Питър

Child2.show_name = функция () (предупреждение ( "Няма да кажа името си");} // Не забравяйте, че можем да променим нашите обекти по всяко време
child2.show_name (); // Няма да казвам името си

Child.show_name (); // Вася - децата не си влияят по никакъв начин


* Този изходен код беше подчертан с Source Code Highlighter.

Можете също да сравните конструктора с баща - той ражда дете, надарявайки го с определени качества, но веднага след създаването детето става напълно независимо от родителя и може да стане много различно от своите братя.
Ако си припомним описанието на типовете данни в началото на статията, тогава става ясно, че Object и неговите подтипове (Function, Array и други) всъщност са конструктори, които дават на създадения обект възможностите на функция, масив и т.н.

Така че това е много по-добре. Вече имаме възможността да създаваме обекти по определен модел. Не всичко обаче е наред. Първо, всеки обект, който създаваме, и всички негови свойства и методи заемат отделно място в паметта, въпреки че в много отношения се повтарят. Второ, какво ще стане, ако искаме да запазим връзката между родител и дете и да можем да променим всички дъщерни обекти наведнъж. На помощ ще ни се притече прототип.

Прототип

Точно както всяко дете има баща и майка (поне биологично), така и всеки обект в JavaScript. И ако бащата, както решихме, работи като дизайнер, то майката е само прототип. Да видим как става това:
направи_ме = функция (_name) (
предупреждение („Бях пуснат“);
това .name = _name;
this .show_name = function () (предупреждение (това .name);)
}
/*
Виждайки ключовата дума на функцията, интерпретаторът проверява кода вдясно от нея и след това всичко е ок - създава нов обект в паметта, което също е наша функция. След това автоматично (без участието на програмиста) се създава свойство прототип за тази функция, което се отнася до празен обект. Ако го направихме ръчно, щеше да изглежда така make_me.prototype = new Object ();

След това даденият обект (посочен от свойството на прототипа) също се добавя автоматично със свойство на конструктора, сочещо обратно към функцията. Оказва се, че това е кръгова връзка.

Сега този обект, който може да бъде описан като (конструктор: ... тук е препратка към функцията ...) - е прототипът на функцията.
*/

// Обектът наистина е обект
предупреждение (typeof make_me.prototype.constructor); // Функцията е нашата функция
предупреждение (make_me.prototype.constructor === make_me); // вярно

// Добавяне на нов метод към прототипа на функцията make_me

Дете = ново make_me ("Вася"); // те ме пуснаха
/ * Сега, в допълнение към всичко описано в предишния пример, в дъщерния обект се създава допълнително скрито свойство [], което сочи към същия обект като make_me.prototype. Защото имотът е скрит, не можем нито да видим стойността му, нито да го променим - обаче той играе важна роля в по-нататъшната работа * /

Сигнал (child.name); //Вася
child.show_name (); //Вася

Child.set_name ("Коля");
/ * Първо, интерпретаторът търси метода set_name на дъщерния обект. Тъй като го няма, той продължава да търси детето. [] Property, намира го там и го стартира. * /
child.show_name (); // Коля - сега Вася се казва Коля :)

Make_me.prototype.show_name2 = функция () (предупреждение („Здравей,“ + това .name;) //T.k. прототипът е обикновен обект, можем да го сменим и в движение

Child2 = new make_me ("Петя");
child2.show_name2 (); // Здравей, Петя
child.show_name2 (); // Здравей Коля - промените в прототипа засягат не само новосъздадените обекти, но и всички стари

Child2.show_name2 = функция () (предупреждение ( "Няма да кажа името си");} // Все още можем да променим самия обект, докато новият метод show_name2 в този обект (и само в него) като че ли ще "презапише" стария метод от прототипа
child2.show_name2 (); // Няма да си казвам името - защото сега имаме наш собствен метод show_name2, след което се извиква и не се извършва търсене в прототипа

Child.show_name2 (); // Здравей, Коля - всичко е още тук

Make_me.prototype = (реквизит: "здравей") // Нека се опитаме да пресъздадем прототипа отново

Сигнал (child.prop); // неопределено
child.show_name2 (); //Здравей Коля
/ * Ако си спомняте какво е работа чрез препратка, тогава всичко е ясно. Повторното създаване на прототипа прекъсва връзката и сега свойството [] на обекта child и child2 сочи към един обект (който беше прототипът на функцията make_me), а свойството make_me.prototype към друг обект, който е новият прототип на функцията make_me * /

Child3 = new make_me ("Олег");
предупреждение (child3.prop); // здравей - както се очакваше


* Този изходен код беше подчертан с Source Code Highlighter.

Както се вижда от примера, докато бащата остава верен на майката (т.е. докато прототипът на функцията остава същият), всички деца зависят от майката и са чувствителни към всички промени в нея. Но щом родителите се разведат (дизайнерът сменя прототипа с друг), децата веднага се разпръскват кой къде и вече няма връзка с тях.

Малко за терминологията
Докато първичната връзка между конструктора и прототипа не бъде прекъсната, можем да наблюдаваме следната картина:

направи_ме = функция (_name) (
предупреждение („Бях пуснат“);
това .name = _name;
this .show_name = function () (предупреждение (това .name);)
}

Make_me.prototype.set_name = функция (_name) (това .name = _name;)
дете = ново make_me ("Вася");

Сигнал (typeof make_me.prototype); // обект - функцията има свойство прототип
предупреждение (typeof child.prototype); // undefined - създаденият обект няма свойство на прототип
предупреждение (child.constructor.prototype === make_me.prototype); // вярно - но обектът има свойство на конструктор, което сочи към конструкторската функция make_me, която от своя страна има свойство прототип


* Този изходен код беше подчертан с Source Code Highlighter.

Както забелязах, след като прочетох много форуми по тази тема, основните проблеми, които хората получават, когато объркат свойството прототип на функция и свойството hidden [] на обект, създаден с тази функция.
И двете от тези свойства са препратки към един и същ обект (стига основната връзка между прототипа и конструктора да не е прекъсната), но въпреки това са различни свойства, с различни имена, едно от тях е достъпно за програмиста, а другото не е.

Винаги е необходимо ясно да се разбере, че ако говорим за прототип на конструктор, тогава това винаги е свойството на прототипа, а ако за прототипа на създадения обект, тогава това е скрито свойство [].

Наследство

Вече знаем, че всеки обект има скрита препратка към прототипа и всеки прототип е обикновен обект.
Най-проницателните читатели вече са уловили миризмата на рекурсия :)
Наистина, тъй като прототипът е обикновен обект, тогава той от своя страна има връзка към своя прототип и т.н. Така се реализира йерархията на прототипа.
птица = функция () () // Това е конструкторът за птици
bird.prototype.cry = функция () (предупреждение ("Кри!");) // Птицата може да крещи
bird.prototype.fly = function () (предупреждение ("Аз летя!");) // и летя

патица = функция () ()
duck.prototype = нова птица ();
duck.prototype.cry = функция () (предупреждение ("Кряк кряк!");) // Патицата крещи различно
duck.prototype.constructor = патица; // Принуди свойството prototype.constructor да бъде настроено на duck, т.к в противен случай ще се отнася до птица

Били = нова патица (); // Били е нашата патица
billy.fly (); //Летя! - Били може да лети, защото е птица
billy.cry (); //Квак Квак! - Били крещи шарлатанче, защото е патица


* Този изходен код беше подчертан с Source Code Highlighter.

По този начин можете да приложите йерархия на всяко ниво на влагане.

Проблем със звездичката

Сега, тъй като знаем толкова много за всичко това, нека се опитаме да разберем колко много се случва в тези три реда.
направи_ме = функция () ()
дете = ново make_me ();
предупреждение (child.toString ()); // изходи

* Този изходен код беше подчертан с Source Code Highlighter.

На първия ред създаваме нова функция и променлива make_me, която сочи към тази функция. Това създава прототип за функцията make_me.prototype, който съдържа свойство на конструктора, сочещо make_me.
Но това не е всичко :)
Защото функцията make_me също е обект, тогава тя от своя страна има татко и майка, т.е. конструктор и прототип. Неговият конструктор е естествена функция на езика Function (), а неговият прототип е обект, съдържащ методи за извикване, прилагане и т.н. - благодарение на този прототип можем да използваме тези методи във всяка функция. Това дава на функцията make_me свойство [], което сочи към Function.prototype.

От своя страна прототипът на конструктора на Function също е обект, чийто конструктор е (изненада!) Object (т.е. Function.prototype. []. Конструктор === Object), а прототипът е обект, съдържащ стандартните свойства и методи на обекта, като toString, hasOwnProperty и други (с други думи - Function.prototype. [] ["hasOwnProperty"] - това е точно същият метод, който можем да използваме във всички производни обекти - и това е точно този, собствен метод на този обект, а не наследен). Ето как откриваме по интересен начин, че всички видове обекти са получени от Object.

Може ли да продължим по-нататък? Оказва се, че не. Object.prototype съдържа основните свойства на обекта именно защото няма собствен прототип. Обект.прототип. [] = Нула; В този момент пътуването през веригата от прототипи за намиране на свойство или метод спира.

Друг интересен факт е, че конструкторът на Object е Function. Тези. Обект. []. Конструктор === Функция.
Има още една кръгова препратка – конструкторът за Object е Function, а конструкторът за Function.prototype е Object.

Да се ​​върнем към нашия пример. Вече разбрахме как се създава функцията, сега нека преминем към втория ред. Там създаваме дъщерен обект, чийто конструктор е функцията make_me, а прототипът е make_me.prototype.

Е, в третия ред виждаме как интерпретаторът върви нагоре по веригата, от дете към дете.[] (Aka make_me.prototype), след това към дете.[] [] (Aka Object.prototype) и вече намира методът toString, който се стартира за изпълнение.

Примеси

Може да изглежда, че наследяването чрез прототипи е единственият начин, по който JavaScript е възможен. Това не е истина.
Имаме работа с много гъвкав език, който предоставя не толкова правила, колкото възможности.

Например, ако искаме, изобщо не можем да използваме прототипи, а да програмираме, използвайки концепцията за миксини. За това нашите добри стари приятели - конструктори ще са полезни.

// Това е човешки конструктор
човек = функция () (
this .live = function () (предупреждение ("Аз живея");) // Човек знае как да живее
this .walk = function () (предупреждение ("Аз вървя");) // Човек може да ходи
}

// Това е конструкторът на поета
поет = функция () (
това .kill = функция () (предупреждение ( "Поетът уби човек");} // Поетът може да убие човек
this .live = function () (предупреждение („мъртъв съм“);) // Това ще доведе до смъртта на човека
}

Владимир = нов човек (); // Владимир е мъж
vladimir.live (); // Живея - той е жив
vladimir.разходка (); // ходя - той ходи

Poet.call (vladimir); // Изпълнете конструктора poet за обекта vladimir
vladimir.kill (); // Поетът уби човека
vladimir.live (); //Аз съм мъртъв

// И сега фокусът
man.call (vladimir);
vladimir.live (); //Аз живея


* Този изходен код беше подчертан с Source Code Highlighter.

Какво виждаме в този пример? Първо, това е способността да се наследява от множество обекти, които не са в една и съща йерархия. В примера има 2 от тях, но може да има колкото искате.
Второ, това е липсата на никаква йерархия. Отменянето на свойства и методи се определя единствено от реда, в който се извикват конструкторите.
Трето, това е способността да променяте обект още по-динамично и това е отделен обект, а не всички потомци, както при промяна на прототипа.

Upd: Затваряния и частни имоти

За да не надувам тази вече доста голяма статия, давам линк към публикацията Затваряния в JavaScript, където е написано малко подробно за това.

Какво да правим с всичко това сега

Както казах по-горе, произволната модификация на отделни обекти, използването на конструктори и миксини, и гъвкавостта на прототипите са просто инструменти, възможности, които позволяват на програмиста да създава код, който е едновременно ужасен и красив във всяко отношение. Важно е само да разберем какви задачи решаваме, с какви средства, какви цели постигаме и каква цена плащаме за това.

Освен това въпросът за цената е доста нетривиален, особено ако говорим за разработка за версии на Internet Explorer 6 и 7.
1. Памет - тук всичко е просто. Във всички браузъри наследяването на прототипи отнема няколко пъти по-малко памет, отколкото при създаване на методи чрез конструктори. Освен това, колкото повече методи и свойства имаме, толкова по-голяма е разликата. Въпреки това си струва да запомним, че ако нямаме хиляда еднакви обекта, а само един, тогава консумацията на памет във всеки случай ще бъде малка, т.к. има и други фактори, които трябва да се вземат предвид тук.
2. Процесорно време – тук основните тънкости са свързани с браузърите на Microsoft.
От една страна, обекти, при които методи и свойства се създават чрез конструктор, могат да бъдат създадени много пъти (в някои случаи десетки или стотици пъти) по-бавно, отколкото чрез прототип. Колкото повече методи, толкова по-бавно. Така че, ако вашият IE замръзне за няколко секунди по време на инициализацията на скрипта - има причина да копаете в тази посока.

От друга страна, собствените методи на обекта (създадени чрез конструктор) могат да се изпълняват малко по-бързо от прототипните. Ако отчаяно трябва да ускорите изпълнението на метод в този браузър, тогава трябва да вземете това предвид. Имайте предвид, че се ускорява извикването на метода (т.е. търсенето му в обекта), а не неговото изпълнение. Така че, ако самият метод работи за секунда, тогава няма да забележите специално увеличение на производителността.

В други браузъри се наблюдават подобни проблеми, където времето за създаване на обекти и извикване на техните методи е приблизително еднакво и за двата подхода.

P.S. Обикновено в статии от този вид авторът предлага някакъв вид обвивка, опитвайки се или да приложи наследяване на клас-обект въз основа на прототип, или просто синтактична захар за прототипно наследяване. Не го правя нарочно, т.к Мисля, че човек, който разбира смисъла на тази статия, може да напише всяка обвивка за себе си и още много интересни неща :)

Етикети: Добавяне на етикети

Обектите са крайъгълният камък на JavaScript. Много вградени типове данни са представени като обекти. За да бъдете успешен разработчик на JavaScript, трябва да имате ясно разбиране за това как работят. Изграждащите блокове на обект се наричат ​​неговите полета или свойства на JavaScript обект. Те се използват за описване на всеки аспект на обект. Имотът може да опише дължината на списъка, цвета на небето или датата на раждане на човек. Създаването на обект е лесен процес. Езикът предоставя синтаксис, известен като обектни литерали, които се означават с къдрави скоби.

Достъп до свойства

Езикът предоставя два записа за достъп до свойства. Първият и най-често срещан е известен като нотация с точки. С точкова нотация може да се осъществи достъп до ресурс чрез посочване на името на хост обекта, последвано от точката и името на свойството. Например, когато на object.foo първоначално е присвоена стойност едно, тогава стойността му ще стане 2, след като JavaScript изразът на обектите бъде изпълнен.

Алтернативен синтаксис за достъп е известен като нотация в скоби. В нотации името на обекта е последвано от набор от квадратни скоби. Те определят името на свойството като низ:

обект ["foo"] = обект ["foo"] + 1.

Той е по-изразителен от нотацията с точки, защото позволява на променлива да указва цялото или част от име на свойство. Това е възможно, защото интерпретаторът на обекти на JavaScript автоматично преобразува този израз в низ и след това извлича съответното свойство. Имената на свойствата се създават в движение чрез обединяване на съдържанието на променливата f с низа "oo":

обект = "бар".

Нотацията със скоби позволява имената на свойствата да съдържат знаци, които не са разрешени в нотацията с точки. Например, следното твърдение е напълно законно в скоби. Ако обаче потребителят се опита да създаде същото име на свойството в нотация с точки, той ще срещне синтактична грешка:

обект [" [защитен с имейл]# $% & * (). "] = вярно.

Свойствата на вложените JavaScript обекти могат да бъдат достъпни чрез свързване на точки и/или скоби. Например, следният обект съдържа вложен обект с име baz, съдържащ друг обект с име foo, който има свойство с име bar, съдържащо стойността пет:

var object = (baz: (foo: (bar: 5))).

Следните изрази имат достъп до вложената лента със свойства. Първият израз използва нотация с точки, докато вторият израз използва квадратна нотация. Третият израз комбинира и двата записа за постигане на същия резултат:

  • object.baz.foo.bar;
  • обект ["baz"] ["foo"] ["bar"];
  • object ["baz"]. foo ["bar"].

Изрази като показания в предишния пример могат да влошат производителността, ако се използват неправилно и да направят JavaScript обекта неизползваем. Оценяването на всеки израз на точка или скоби отнема време. Ако едно и също свойство се използва няколко пъти, тогава има смисъл да получите достъп до свойството веднъж и след това да съхраните стойността в локална променлива за всички бъдещи цели.

Функция като метод

Когато функцията се използва като свойство на обект, тя се нарича метод. Подобно на свойствата, те се специфицират с помощта на литерална нотация на обекта. Например:

var обект = (сума: функция (foo, bar) (връщане foo + bar;)).

Обектните методи на JavaScript могат да бъдат извикани с помощта на етикети и скоби. Следният пример извиква метода sum () от предишния пример, използвайки и двете нотации:

  • обект.сума (1, 2);
  • обект ["сума"] (1, 2).

Литералната нотация на обекта е полезна за създаване на нови обекти, но не може да добавя свойства или методи към съществуващи. За щастие добавянето на нови данни е толкова лесно, колкото създаването на оператор за присвояване. Създава се празен обект. След това, използвайки оператори за присвояване, се добавят две свойства, foo и bar, както и методът baz:

  • var обект = ();
  • object.foo = 1;
  • object.bar = нула;
  • object.baz = функция () (връщане "здравей от baz ()";).

Капсулиращи програми

Основната идея зад обектно-ориентираното програмиране е да се разделят програмите на по-малки части и да се направи всеки отговорен за управлението на собственото си състояние. По този начин някои познания за това как работи част от програмата може да са локални за тази част. Някой, който работи по останалата част от програмата, не трябва да помни или дори да знае за нея. Всеки път, когато тези локални данни се променят, трябва да се актуализира само кодът непосредствено около тях.

Различните части на такава програма взаимодействат помежду си чрез интерфейси, ограничен набор от функции или връзки, които предоставят полезна функционалност на по-абстрактно ниво, криейки тяхното точно изпълнение. Такива части на програмата се моделират с помощта на обекти. Техният интерфейс се състои от специфичен набор от методи и свойства. Свойствата, които са част от интерфейс, се наричат ​​публични свойства. Останалите, които не трябва да докосват външен код, се наричат ​​частни.

Много езици предоставят възможност за разграничаване между публични и частни свойства и не позволяват на външен код за достъп до частни свойства. JavaScript, отново използвайки минималистичен подход, все още не е постигнат. В момента се работи по добавянето на този език. Следователно JavaScript програмистите ще използват тази идея успешно. По правило наличният интерфейс е описан в документацията или коментарите. Също така е обичайно да се поставя долно черта (_) в началото на имената на свойствата, за да се посочи, че свойствата са частни. Разделянето на интерфейса от реализацията е страхотна идея. Обикновено се нарича капсулиране.

Имоти

Обект със скоби (...) се нарича обектен литерал. Можете веднага да поставите някои свойства в такива скоби (...). Например, сдвоява "ключ: стойност и така нататък":

let user = (// име на обект: "John", // по ключ "name" съхранява стойността "(! LANG: John" age: 30 // by key "age" store value 30 }.!}

Свойството има ключ (известен също като "име" или "идентификатор") преди двоеточие ":" и стойност вдясно от него. Потребителският обект има две свойства. Полученият потребителски обект на JavaScript с два подписани файла с етикет „име“ и „възраст“. Можете да добавяте, изтривате и четете файлове от него по всяко време. Стойностите на свойствата са достъпни чрез нотация с точки. Тя може да бъде от всякакъв вид. Може да се добави булева. За да изтриете свойство, използвайте delete в случай на грешка на JavaScript обект.

Всички обекти за грешки в JavaScript са наследници на обекта Error или наследен обект:

  1. Обектът Syntax Error се наследява от обекта Error.
  2. Грешка при анализа на JSON на конкретен тип обект на синтактична грешка.

За да се потопите още по-дълбоко в това как приложенията се справят с грешките в JavaScript, разгледайте по-отблизо Airbrake JavaScript, инструмент за проследяване на грешки за сигнали в реално време и моментално разбиране какво се обърка с JavaScript кода.

Съобщения за грешка, които потребителят може да получи, преди да изтрие JavaScript обект:

  1. Лош контролен знак в низовия литерал.
  2. Лош символ в низов литерал.
  3. Лош изход на Unicode.
  4. Лош герой за бягство.
  5. Незавършен низ.
  6. Неочакван нецифров код.
  7. Няма цифри след десетичната запетая.
  8. Незавършено дробно число.
  9. След индикатора за степен няма цифри.
  10. Няма цифри след знака на степента.
  11. Експоненциалната част няма номер.
  12. Неочакван край на данните.
  13. Неочаквана ключова дума.
  14. Неочакван символ.
  15. Край на данните при четене на съдържанието на обекта.
  16. Очакваното име на свойството или ")".

Изчислителни свойства

Можете да използвате квадратни скоби в обектен литерал. Това се нарича изчислени свойства. По-долу е показан пример.

Изчислената стойност на свойството е проста: това означава, че името на свойството трябва да бъде взето от плод. Така че, ако посетител влезе в "ябълка", чантата става (ябълка: 5). Можете да използвате по-сложни изрази в квадратни скоби:

нека плод = "ябълка";

: 5 // bag.appleComputers = 5

Квадратните скоби са много по-мощни от нотацията с точки. Те приемат имена на свойства и променливи. Но те също са по-тромави за писане. Следователно, през повечето време, когато имената на свойствата са известни и прости, се използва точка. И ако имате нужда от нещо по-сложно, тогава преминете към квадратни скоби.

Резервация на думи

Променливата не може да има име, равно на една от запазените думи като for, let, return и т.н. Но няма такова ограничение при сортиране на JavaScript обекти.


По принцип всяко име е позволено, но има специално: то "__proto__" получава специално третиране по исторически причини. Например, не можете да го зададете на стойност, различна от обект:

obj .__ proto__ = 5;

предупреждение (obj .__ proto__); //, не работи по предназначение

Както можете да видите от кода, присвояването на примитив 5 се игнорира. Това може да стане източник на грешки и дори уязвимости, ако операторът възнамерява да съхранява произволни двойки ключ-стойност в обекта и да позволи на посетителя да посочи ключовете. В този случай посетителят може да избере "proto" като ключ и да го добави към JavaScript обекта. Има начин да направите обекти, третирани с __proto__ като редовно свойство. Има и друга карта на структури от данни, които поддържат произволни ключове.

Целочислени свойства

Терминът "целочислено свойство" тук означава низ, който може да бъде преобразуван от цяло число без промяна. Така, например, "49" е име на цяло число, защото когато се преобразува в цяло число и обратно, то все още е същото. Но "+49" и "1.2" не са. От друга страна, ако ключовете не са цели числа, тогава те са изброени в реда на създаване. Вижте примера по-долу.


За да разрешите проблема с регионалните кодове, можете да „измамите“, като направите кодовете нецелочислени. Достатъчно е добавянето на "+" (знак плюс) пред всеки код. Сега ще работи по предназначение.

Разликата между обекти и примитиви е, че те се съхраняват и копират "чрез препратка". Примитивните стойности се присвояват и копират "като цяло число". Променливата съхранява "адрес в паметта", а не самия обект или "препратка" към него. Можете да използвате всяка променлива за достъп и промяна на нейното съдържание.


Горният пример показва, че има само един обект и администратор за влизане в него. След това, ако по-късно използва различен ключ (потребител), потребителят ще открие промяната.

Операторите за равенство == и строгото равенство === работят по същия начин за обекти. Два обекта са равни само ако са един и същ обект. За сравнения като obj1> obj2 или за сравнения с примитива obj == 5, обектите се преобразуват в примитиви. Честно казано, подобни сравнения са много рядко необходими и обикновено са резултат от грешка в кодирането.

Проверка на обекти на JavaScript

Обектите имат достъп до всяка собственост. Ако обаче изобщо не съществува, няма да е грешка. Само достъпът до несъществуващо свойство връща недефиниран. Той предоставя много често срещан начин за проверка на свойство и сравняване с недефиниран. По-долу е даден пример.


Използване на "in" за свойства, които съхраняват недефинирани. Обикновено строгата проверка за сравнение "=== undefined" работи добре. Има специален случай, когато той се проваля и "in" работи правилно. Това е, когато свойството на обект съществува, но остава недефинирано.


В горния код свойството obj.test технически съществува. Следователно операторът in работи правилно. Ситуации като тази са много редки, защото undefined обикновено не се присвоява. Използват се предимно нулеви "неизвестни" или "празни" стойности. По този начин операторът in всъщност е гост в кода.

Цикъл "for..in"

За да преминете през всички ключове от обект на обект, има специална форма на цикъл: for..in. Това е нещо съвсем различно от конструкцията for (;;).

По-долу е даден пример.


Трябва да се отбележи, че всички конструктори "for" ви позволяват да декларирате променливата за цикъл вътре в цикъла като ключ let. Като алтернатива можете да използвате различен ключ за име на променлива.

Например, for (нека prop в obj) също е широко използван.

Има алтернативна "квадратна скоба", която работи на всеки низ.


Като се има предвид това, въпросът изисква ключовете на JavaScript обекта да бъдат валиден идентификатор на променлива, тоест да няма интервали или други ограничения. Трябва да обърнете внимание, че линията вътре в скобите е правилно цитирана. Квадратните скоби също предоставят начин за получаване на име на свойство от всеки израз, за ​​разлика от литерален низ от променлива:

let key = "харесва птици";

// същото като потребителя ["харесва птици"] = true;

потребител = вярно.

Тук променливият ключ може да бъде изчислен по време на изпълнение и зависи от въвеждането на потребителя и след това да се използва за достъп до свойството. Това дава на програмистите голяма гъвкавост. Точковата нотация не може да се използва по подобен начин, тъй като тя ще итерира над JavaScript обекта. По-долу е даден пример.


Const обект

Декларираният const обект може да бъде променен. По-долу е показан пример.


Може да изглежда, че JavaScript обект на линия (*) ще изведе грешка, но не. Това е така, защото const улавя стойността на самия потребител. И тук потребителят поддържа препратка към един и същ обект през цялото време. Редът (*) влиза вътре в обекта, не се преназначава от потребителя. Const ще даде грешка, ако се опитате да зададете потребител и нещо друго. Клонирайки и сливайки, Object.assign създава друга препратка към същия обект, в случай че трябва да бъде дублиран. Това също е изпълнимо, но малко по-сложно, защото няма вграден метод в JavaScript. Всъщност това рядко се налага. В повечето случаи се използва копиране чрез препратка. Но ако наистина имате нужда от него, тогава трябва да създадете JavaScript обект и да репликирате структурата на съществуващия, като копирате неговите свойства на примитивно ниво. По-долу е даден пример.


И можете също да използвате метода Object.assign за това. Аргументите dest и src1, ..., srcN са обекти. Той копира свойствата на всички обекти src1, ..., srcNINTO dest. С други думи, свойствата на всички аргументи, започващи от втория, се копират в първия. След това се връща към дестинацията. Например, можете да го използвате, за да комбинирате няколко обекта в един.


Освен това е възможно да се използва Object.assign за замяна на обикновения цикъл за клониране. Той копира всички потребителски свойства в празен обект и го връща, точно като цикъл, но по-кратък. Досега всички потребителски свойства се приемаха за примитивни. Но свойствата могат да бъдат препратки към други обекти.

За да коригирате това, трябва да използвате цикъл за клониране, който проверява всяка потребителска стойност и, ако е обект, след това репликира неговата структура. Това се нарича "дълбоко клониране".

Има стандартен алгоритъм за дълбоко клониране, който обработва горния случай и по-сложни случаи, наречени алгоритъм за структурирано клониране. За да избегнете преоткриването на колелото, можете да използвате работеща реализация от библиотеката на lodash JavaScript, наречена _.cloneDeep (obj).

Разширени техники

Ако програмист обикаля обект и се стреми да получи всички свойства в същия ред, в който са добавени, той може да разчита на „специален ред“, при който целочислените свойства се сортират, а други се формират в реда, в който е създаден JavaScript обектът .

Разширените обективни методи се занимават с концепции, които рядко се използват в JavaScript. Това е така, защото тези мощни функции не са необходими в нормални сценарии. Някои от тези методи може да не работят в по-стари браузъри, като например ранните версии на Netscape 4.

Използването на прототипа може да се използва за създаване на JavaScript обекти и всички методи на mycircle, а не само нови. Това дава смесено натоварване на производителността. Те не трябва да съхраняват отделни копия на методите за всеки екземпляр на обекта, така че може да изискват по-малко памет, за да работят, но браузърът трябва да търси текущия и родителския обхват, за да ги намери. Това може да доведе до изключителна латентност. Обикновено потребителят трябва да използва това, което е подходящо за кода, вместо да базира това решение на производителността, освен ако не се занимава с много специфична контролирана среда.


Върнете вярно

В някои случаи може да е необходимо свойство на обект да бъде обвързано със самия обект или някъде във веригата на прототипа. В JavaScript всички обекти използват метода hasOwnProperty, който връща true, ако това свойство е обвързано с един екземпляр на обект. В този случай става възможно да се провери дали конструкторът на обекта има същото свойство със същата стойност като самия екземпляр на обекта. Това може да даде грешен резултат, ако има отделни свойства на JavaScript обект със същата стойност както за екземпляра на обекта, така и за прототипа на веригата. Методът hasOwnProperty приема единичен параметър, името на свойството като низ.


Частните методи могат да бъдат създадени по същия начин. Това е просто функция, която се създава вътре в конструкторска функция. Това може да изглежда объркващо за някои, но ето как работи. Частна функция може да бъде извикана само от самия конструктор или от методи, които са дефинирани в низа. Те могат да се използват като публични методи, ако са присвоени на публичен конструктор и достъпни чрез публични методи на Javascript обекти.

функция myob () (функция cantBeSeen () (предупреждение (secretValue);

) var secretValue = "";

this.method1 = функция () (secretValue = "(! LANG: без изненади";!}

this.method2 = cantBeSeen;

) var oneOb = new myob ();

oneOb.method1 ();

// сигнали "без изненади" oneOb.method2 ();

// предупреждава "без изненади".

Команден шаблон

Командните обекти позволяват слабо свързани системи, отделяйки тези, които издават заявката от обектите и всъщност обработват заявката. Тези заявки се наричат ​​събития, а кодът, който обработва заявките, се нарича манипулатори на събития.

Да предположим, че създавате приложения, които поддържат действията на клипборда Изрязване, Копиране и Поставяне. Тези действия могат да се задействат по различни начини в приложението: от системата от менюта, контекстните менюта, например чрез щракване с десния бутон върху текстово поле или чрез клавишни комбинации. Командните обекти ви позволяват да централизирате обработката на тези действия, по една за всяка операция, когато имате нужда само от една команда за обработка на всички заявки за изрязване, една за всички заявки за копиране и една за всички заявки за поставяне.

Тъй като командите централизират цялата обработка, те също често участват в обработката на функциите за анулиране за цялото приложение. Значителни подобрения могат да бъдат постигнати чрез прилагане на съвременни техники на JavaScript, което води до по-ефективни, надеждни и поддържащи се приложения.

JavaScript + jQuery шаблони могат да се използват, за да видите как да направите това. Този уникален пакет включва оптимизиран JavaScript за всички GoF шаблони, използващи по-разширени функции като пространства от имена, прототипи, модули, функционални обекти, затваряния, анонимни функции и др. Ако потребителите искат най-новите инструменти и техники за JavaScript шаблони, jQuery шаблони и шаблонни архитектури, тогава това е най-добрият случай на използване. Този пакет съдържа ценна, подходяща информация за разработчиците на JavaScript. Ето какво е включено:

  1. JavaScript оптимизирани GoF шаблони.
  2. Модерни шаблони за дизайн на JavaScript.
  3. Модели за изглед на дизайн.
  4. JQuery шаблони за дизайн.
  5. Архитектурни модели JavaScript идиоми.
  6. Примерни приложения (MVC, SPA и др.)

Предложените основи на синтаксиса на обекти на JavaScript са много важни за начинаещите програмисти. Първо трябва да разберете обектите, след това ще имате познания за обектно-ориентирано програмиране. Наложително е да имате задълбочено разбиране на този материал, тъй като той служи като основа за останалата част от езика на JavaScript.

Обектът е неподредена колекция от свойства. Свойството е част от обект, който симулира променлива. Свойството се състои от име и стойност.

Има три категории обекти в JavaScript:

  • Обекти от базов типОбекти са дефинирани в спецификацията на ECMAScript. Например обекти от тип Array, Function, Date или RegExp са обекти от основния тип.
  • Обекти по време на изпълнениеОбекти ли са дефинирани по време на изпълнение (като браузър). Например обектите от тип HTMLElement са обекти по време на изпълнение.
  • Персонализирани обектиВсеки обект е създаден чрез изпълнение на JavaScript код.

Създаване на обект

Обект може да бъде създаден с помощта на обектен литерал или оператора new с конструктор.

Обектният литерал е разделен със запетая списък с нула или повече свойства (име: двойки стойности), затворен в къдрави скоби. Името на свойството може да бъде всеки валиден идентификатор, низов литерал (можете да използвате празен низ) или число. Имената на числови свойства автоматично се преобразуват в низове. Стойността на свойството може да бъде стойност от произволен тип или израз (стойността на свойството в този случай ще бъде резултат от оценката на израза):

// Създаване на празен обект var o = (); // Създаване на обект с три свойства var user = (име: "Homer", "age": 45, 1: true);

Създаване на обект с помощта на оператора new:

Var o = нов обект ();

Обектни операции

Основните операции, извършвани с обекти, са добавяне на нови свойства, промяна на съществуващи свойства, изтриване на свойства и достъп до свойства.

Можете да добавите ново свойство към обект, като присвоите стойност на свойството. За да присвоите стойност на дадено свойство, той трябва да бъде достъпен. Един от операторите за достъп се използва за достъп до свойството:. (точка) или (квадратни скоби):

Достъпът до свойство и промяната на стойност се извършва по същия начин (с помощта на оператори за достъп):

Var o = (x: 5); предупреждение (o.x); // Извикване на сигнал за свойство (o ["x"]); // Достъп до свойството o.x = 10; // Променете стойността

Изтриването на свойство се извършва с помощта на оператора delete:

Var o = (x: 5); предупреждение („x“ в o); // истинско изтриване o.x; предупреждение („x“ в o); // невярно

За итерация върху свойствата на обект се използва цикъл for-in:

Var obj = (x: 5, y: 10, str: "Здравей!"); for (var prop в obj) (предупреждение (prop);)

Обектни методи

Свойство, чиято стойност е функция, се нарича метод. Извикването на метод се извършва по същия начин като обикновеното извикване на функция - с помощта на оператора () (оператор на повикване):

Var o = (sayHi: function () (предупреждение ("Здравей!");)); o.sayHi (); // "Здравейте!"

Ключовата дума this се използва за достъп до свойствата на обект вътре в метод. Той съдържа препратка към обекта, с който е извикан методът:

Var o = (име: "Homer", кажетеName: функция () (предупреждение (това. име);)); o.sayName (); // "Омир"

Вместо тази ключова дума можете да използвате директно името на обекта, но това не е много удобно, защото ако името на обекта се промени, ще трябва да промените и името в методите:

Var o = (име: "Homer", кажетеName: функция () (предупреждение (o.name);)); o.sayName (); // "Омир"