11 најпопуларнијих (и више!) ЈаваСцрипт функција које морате знати

Шифра паметна! Будите бржи, продуктивнији и срећнији ЈаваСцрипт програмер тако што ћете савладати ове најважније функције које се понављају у језику.

Било да је бацкенд или фронтенд (или чак свемирски бродови), ЈаваСцрипт је свуда. Такође је прилично флексибилан језик (што значи да има хардцоре функционалне шеме програмирања као и добре старе класе), а његова сличност са другим језицима „сличним Ц“ омогућава лак прелазак програмера са других језика.

Ако желиш ниво ваше ЈС игре, предлажем да научите, вежбате и на крају савладате следеће основне функције доступне на језику. Нису сви ови стриктно „потребни“ за решавање проблема, али у неким случајевима могу учинити много за вас, док у другим могу смањити количину кода који морате да напишете.

Мапа()

Било би јерес написати чланак о важним ЈаваСцрипт функцијама и не помињати мап()! 😆😆 Заједно са филтер() и редуцирај(), мап() чини својеврсно свето тројство. Ово су функције које ћете стално користити у својој каријери, тако да су више него вредне пажње. Хајде да их се позабавимо једним по једним, почевши од мап().

мап() је међу оним функцијама које задају највише проблема људима који уче ЈаваСцрипт. Зашто? Не зато што постоји нешто инхерентно сложено у вези са тим, већ зато што је начин на који ова функција функционише идеја преузета из онога што се зове функционално програмирање. А пошто нисмо изложени функционалном програмирању — наше школе и индустрија су пуне објектно оријентисаних језика — наш пристрасни мозак функционише чудно или чак погрешно.

ЈаваСцрипт је далеко функционалнији од објектно оријентисаног, иако његове модерне верзије дају све од себе да сакрију ову чињеницу. Али то је цела конзерва црва коју могу да отворим можда неког другог дана. 🤣 У реду, дакле, мап() . . .

мап() је веома једноставна функција; она се везује за низ и помаже нам да конвертујемо сваку ставку у нешто друго, што резултира новим низом. Како тачно конвертовати ставку је наведено као друга функција, која је по конвенцији анонимна.

То је све! На синтаксу је можда потребно неко навикавање, али у суштини то је оно што радимо у функцији мап(). Зашто бисмо могли да користимо мап()? Зависи шта покушавамо да постигнемо. На пример, рецимо да смо забележили температуру за сваки дан прошле недеље и сачували је као једноставан низ. Међутим, сада нам је речено да инструменти нису били баш прецизни и да су пријавили 1,5 степени нижу температуру него што је требало.

Ову исправку можемо да урадимо помоћу функције мап() овако:

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const correctedWeeklyReadings = weeklyReadings.map(reading => reading + 1.5);

console.log(correctedWeeklyReadings); // gives [ 21.5, 23.5, 22, 20.5, 22.5, 23, 24.5 ]

Још један, веома практичан пример долази из света Реацт-а, где је креирање листа ДОМ елемената из низова уобичајен образац; дакле, овако нешто је уобичајено:

export default ({ products }) => {
    return products.map(product => {
        return (
            <div className="product" key={product.id}>
                <div className="p-name">{product.name}</div>
                <div className="p-desc">{product.description}</div>
            </div>
        );
    });
};

Овде имамо функционалну Реацт компоненту која прима листу производа као своје реквизите. Из ове листе (низа) затим прави листу ХТМЛ „див-ова“, у суштини претварајући сваки објекат производа у ХТМЛ. Оригинални предмет производа остаје нетакнут.

Можете тврдити да мап() није ништа друго до прослављена фор петља и били бисте потпуно у праву. Али приметите да чим изнесете тај аргумент, говори ваш објектно оријентисани обучени ум, док ове функције и њихово образложење потичу из Функционалног програмирања, где су униформност, компактност и елеганција веома цењени. 🙂

филтер()

филтер() је веома корисна функција коју ћете примењивати изнова и изнова у многим ситуацијама. Као што име сугерише, ова функција филтрира низ на основу правила/логике коју наведете и враћа нови низ који садржи ставке које задовољавају та правила.

Хајде да поново употребимо наш пример времена. Претпоставимо да имамо низ који садржи максималне температуре за сваки дан прошле недеље; сада желимо да сазнамо колико је тих дана било хладније. Да, „хладније“ је субјективан појам, па рецимо да тражимо дане у којима је температура била испод 20. То можемо урадити помоћу функције филтер() овако:

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const colderDays = weeklyReadings.filter(dayTemperature => {
    return dayTemperature < 20;
});

console.log("Total colder days in week were: " + colderDays.length); // 1

Имајте на уму да анонимна функција коју прослеђујемо филтер() мора да врати Булову вредност: тачно или нетачно. Овако ће филтер() знати да ли да укључи ту ставку у филтрирани низ. Слободни сте да напишете било коју количину сложене логике унутар ове анонимне функције; можете да упућујете АПИ позиве и читате корисничке уносе, и тако даље, све док се уверите да на крају враћате Булову вредност.

Пазите: Ово је споредна напомена коју сам приморан да пружим на основу свог искуства као ЈаваСцрипт програмера. Било да је то због аљкавости или погрешних основа, многи програмери стварају суптилне грешке у својим програмима када користе филтер(). Хајде да поново напишемо претходни код да садржи грешку:

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const colderDays = weeklyReadings.filter(dayTemperature => {
    return dayTemperature < 20;
});

if(colderDays) {
    console.log("Yes, there were colder days last week");
} else {
    console.log("No, there were no colder days");
}

Приметили сте нешто? Одличан посао ако јесте! Услов иф при крају проверава цолдерДаис, што је заправо низ! Изненадићете се колико пута људи направе ову грешку док се утркују да испоштују рокове или код лошег расположења (из било ког разлога). Проблем са овим условом је у томе што је ЈаваСцрипт на много начина чудан и недоследан језик, а „истинитост“ ствари је један од њих. Док [] == труе враћа фалсе, што вас наводи да мислите да горњи код није покварен, реалност је да унутар услова ако, [] оцењује као истинито! Другим речима, шифра коју смо написали никада неће рећи да прошле недеље није било хладнијих дана.

  Погледајте седишта за концерте и стадионе у ВР пре него што купите карте [iOS]

Исправка је врло једноставна, као што је дато у коду пре горњег кода. Проверавамо цолдерДаис.ленгтх, што нам гарантује цео број (нула или више) и на тај начин ради доследно у логичким поређењима. Имајте на уму да ће филтер() увек, увек, увек враћати низ, празан или непразан, тако да се можемо ослонити на то и са сигурношћу писати наша логичка поређења.

Био је то дужи заобилазни пут него што сам планирао, али грешке попут ове вреди истакнути у десет хиљада речи, великим словима ако је потребно. Надам се да вас ово неће угристи и да ћете уштедети стотине сати напора за отклањање грешака! 🙂

смањити()

Од свих функција у овом чланку, као иу стандардној ЈаваСцрипт библиотеци, редукција() је међу водећим за круне „збуњујућег и чудног“. Иако је ова функција веома важна и резултира елегантним кодом у многим ситуацијама, већина ЈаваСцрипт програмера је избегава и уместо тога радије пишу детаљнији код.

Разлог је тај — и овде ћу бити искрен! — смањити() је тешко разумети, иу смислу концепта и у смислу извршења. Када прочитате његов опис, прочитали сте га неколико пута и још увек сумњате да ли сте га погрешно прочитали; а када га видите у акцији и покушате да замислите како функционише, ваш мозак се уврће у хиљаду чворова! 🤭

Сада, немој да се плашиш. Функција редуцира () није ни близу по сложености и застрашивању, рецимо, Б+ Треес и њихови алгоритми. Само што се оваква логика ретко среће током свакодневног посла просечног програмера.

Дакле, пошто сам вас уплашио дању светлост и одмах вам рекао да не бринете, коначно бих желео да вам покажем шта је ова функција и зашто би нам тачно могла затребати.

Као што име каже, редукција() се користи за, па, смањење нечега. Оно што смањује је низ, а оно на шта своди дати низ је једна вредност (број, низ, функција, објекат, било шта). Ево једноставнијег начина да се то изрази — редуцира() трансформише низ у једну вредност. Имајте на уму да повратна вредност из редукције() није низ, што је случај са мап() и филтер(). Схватити оволико је већ пола битке. 🙂

Сада је некако очигледно да ако желимо да трансформишемо (смањимо) низ, морамо да обезбедимо неопходну логику; а на основу вашег искуства као ЈС програмера, највероватније сте већ претпоставили да то радимо помоћу функције. Ова функција је оно што зовемо редукторска функција, која формира први аргумент редукције(). Други аргумент је почетна вредност, као што је број, стринг, итд. (Ускоро ћу објаснити шта је, дођавола, ова „почетна вредност“).

На основу нашег досадашњег разумевања, можемо рећи да позив редукције() изгледа овако: арраи.редуце(редуцерФунцтион, стартингВалуе). Хајде сада да се позабавимо суштином целе ствари: функцијом редуктора. Као што је већ утврђено, функција редуктора је оно што говори редукцији () како да конвертује низ у једну вредност. Потребна су два аргумента: променљива која делује као акумулатор (не брините, објаснићу и овај део), и променљива за чување тренутне вредности.

Знам, знам . . . то је било много терминологије за једну функцију која није ни обавезна у ЈаваСцрипт-у. 😝😝 И зато људи беже од редукције(). Али ако га научите корак по корак, не само да ћете га разумети већ и ценити док постанете бољи програмер.

У реду, да се вратимо на тему. „Почетна вредност“ која се прослеђује редукцији() је . . . па, почетна вредност за прорачун који желите да користите. На пример, ако ћете радити множење у редукторској функцији, почетна вредност од 1 има смисла; као додатак, можете почети са 0 и тако даље.

Сада погледајмо потпис за функцију редуктора. Функција редуктора која се прослеђује редукцији() има следећи облик: редукторФункција(акумулатор, тренутнаВалуе). „Акумулатор“ је само фенси назив за променљиву која прикупља и чува резултат израчунавања; то је исто као да користите променљиву која се зове тотал за сумирање свих ставки у низу користећи нешто попут тотал += арр[i]. Овако се примењује функција редуктора у редукцији(): акумулатор је иницијално подешен на почетну вредност коју сте дали, а затим се један по један посећују елементи низа, врши се израчунавање, а резултат се чува у акумулатор, и тако даље. . .

Дакле, која је то „тренутна вредност“ у редукторској функцији? То је иста идеја коју бисте у мислима замислили ако бих вас замолио да пређете низ: узели бисте променљиву да почне од индекса нула и померали бисте је корак по корак напред. Док то радите, ако вас замолим да изненада престанете, нашли бисте се на једном од елемената низа, зар не? Ово је оно што подразумевамо под тренутном вредношћу: то је вредност променљиве која се користи за представљање ставке низа која је тренутно у разматрању (замислите да пређете преко низа ако то помаже).

Уз све то речено, време је да видимо једноставан пример и видимо како се сав овај жаргон спаја у стварном позиву редукције(). Рецимо да имамо низ који садржи првих н природних бројева (1, 2, 3… н) и да смо заинтересовани да пронађемо факторијел од н. Знамо да нађемо н! једноставно морамо све помножити, што нас доводи до ове имплементације:

const numbers = [1, 2, 3, 4, 5];
const factorial = numbers.reduce((acc, item) => acc * item, 1);
console.log(factorial); // 120

Много тога се дешава у ова само три реда кода, па хајде да то распакујемо један по један у контексту (веома дуге) расправе коју смо до сада водили. Као што је очигледно, бројеви су низ који садржи све бројеве које желимо да помножимо. Затим погледајте позив нумберс.редуце(), који каже да почетна вредност за ацц треба да буде 1 (јер не утиче нити уништава било какво множење). Затим проверите тело функције редуктора, `(ацц, итем) => ацц * итем, што једноставно каже да повратна вредност за сваку итерацију преко низа треба да буде та ставка помножена са оним што је већ у акумулатору. Итерација и стварно складиштење множења експлицитно у акумулатору је оно што се дешава иза кулиса, и један је од највећих разлога зашто је редукција() такав камен спотицања за ЈаваСцрипт програмере.

  Колико кошта провера прошлости?

Зашто користити редуцира ()?

То је заиста сјајно питање и да будем искрен, немам сигуран одговор. Шта год да редуцира() може да се уради кроз петље, форЕацх(), итд. Међутим, те технике резултирају много више кода, што отежава читање, посебно ако сте у журби. Затим постоји брига за непроменљивост: са редукцијом() и сличним функцијама, можете бити сигурни да ваши оригинални подаци нису мутирани; ово само по себи елиминише читаве класе грешака, посебно у дистрибуираним апликацијама.

Коначно, редукција() је далеко флексибилнија, у смислу да акумулатор може бити објекат, низ или чак функција ако је потребно; исто важи и за почетну вредност и друге делове позива функције — скоро све може да уђе, а скоро све може да изађе, тако да постоји изузетна флексибилност у дизајнирању кода за вишекратну употребу.

Ако још увек нисте убеђени, и то је сасвим у реду; сама ЈаваСцрипт заједница је оштро подељена око „компактности“, „елеганције“ и „моћи“ редукције(), тако да је у реду ако је не користите. 🙂 Али обавезно погледајте неке уредни примери пре него што одлучите да бин смањите().

неки()

Рецимо да имате низ објеката, при чему сваки објекат представља особу. Желите да знате да ли у низу има људи који су старији од 35 година. Имајте на уму да нема потребе да бројите колико је таквих људи, а камоли да преузимате њихову листу. Оно што овде говоримо је еквивалент „један или више” или „најмање један”.

Како то радиш?

Да, можете креирати променљиву заставице и прећи преко низа да бисте решили овај проблем на следећи начин:

const persons = [
    {
        name: 'Person 1',
        age: 32
    },
    
    {
        name: 'Person 2',
        age: 40
    },
];

let foundOver35 = false;

for (let i = 0; i < persons.length; i ++) {
    if(persons[i].age > 35) {
        foundOver35 = true;
        break;
    }
}

if(foundOver35) {
    console.log("Yup, there are a few people here!")
}

Проблем? По мом мишљењу, код је превише сличан Ц или Јава. „Вербосе“ је још једна реч која ми пада на памет. Искусни ЈС можда мисли на „ружно“, „ужасно“ итд. 😝 И с правом, тврдио бих. Један од начина да се побољша овај део кода је да се користи нешто попут мапе(), али чак и тада решење је мало незграпно.

Испоставило се да имамо прилично уредну функцију под називом соме() која је већ доступна у основном језику. Ова функција ради низове и прихвата прилагођену функцију „филтрирања“, враћајући Боолеан вредност труе или фалсе. У суштини, ради оно што смо покушавали да урадимо последњих неколико минута, само врло сажето и елегантно. Ево како га можемо користити:

const persons = [
    {
        name: 'Person 1',
        age: 32
    },
    
    {
        name: 'Person 2',
        age: 40
    },
];

if(persons.some(person => {
    return person.age > 35
})) {
    console.log("Found some people!")
}

Исти унос, исти резултат као и раније; али приметите огромно смањење кода! Обратите пажњу и на то колико је когнитивно оптерећење драстично смањено јер више нема потребе да рашчлањамо код ред по ред као да смо сами тумач! Код се сада скоро чита као природни језик.

сваки()

Баш као и соме(), имамо још једну корисну функцију која се зове евери(). Као што до сада можете претпоставити, и ово враћа Булову вредност у зависности од тога да ли све ставке у низу пролазе дати тест. Наравно, тест који треба проћи се испоручује као анонимна функција већину времена. Поштедећу вас бола око тога како би наивна верзија кода могла да изгледа, па ево како се користи сваки():

const entries = [
    {
        id: 1
    },
    
    {
        id: 2
    },
    
    {
        id: 3  
    },
];

if(entries.every(entry => {
    return Number.isInteger(entry.id) && entry.id > 0;
})) {
    console.log("All the entries have a valid id")
}

Као што је очигледно, код проверава све објекте у низу да ли је исправно својство ИД-а. Дефиниција „важеће“ зависи од контекста проблема, али као што видите, за овај код сам узео у обзир ненегативне целе бројеве. Још једном видимо колико је код једноставан и елегантан за читање, што је једини циљ ове (и сличних) функција.

укључује()

Како проверавате постојање подстрингова и елемената низа? Па, ако сте попут мене, брзо посегнете за индекОф(), а затим потражите документе да бисте сазнали његове могуће повратне вредности. То је велика непријатност, а повратне вредности је тешко запамтити (брзо — шта значи процес који враћа 2 оперативном систему?).

Али постоји лепа алтернатива коју можемо искористити: укључује(). Употреба је једноставна као и име, а резултујући код је изузетно дирљив. Имајте на уму да се подударање врши помоћу инцлуде() осетљивог на велика и мала слова, али претпостављам да је то оно што сви интуитивни ионако очекујемо. А сада, време је за неки код!

const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(4));
const name = "Ankush";
console.log(name.includes('ank')); // false, because first letter is in small caps
console.log(name.includes('Ank')); // true, as expected

Међутим, не очекујте превише од ове скромне методе:

const user = {a: 10, b: 20};
console.log(user.includes('a')); // blows up, as objects don't have a "includes" method

Не може да гледа унутар објеката јер једноставно није дефинисан за објекте. Али хеј, знамо да ради на низовима, па можда можемо да направимо неке трикове овде. . . 🤔.

const persons = [{name: 'Phil'}, {name: 'Jane'}];
persons.includes({name: 'Phil'});

Дакле, шта се дешава када покренете овај код? Не експлодира, али резултат је такође разочаравајући: лажно. 😫😫 Заправо, ово има везе са објектима, показивачима и начином на који ЈаваСцрипт види и управља меморијом, што је свет за себе. Ако желите да зароните дубље, слободно се упустите (можда почните овде), али зауставићу се овде.

Горњи код можемо учинити да се понаша ако га препишемо на следећи начин, али у овом тренутку, по мом мишљењу, мање-више постаје шала:

const phil = {name: 'Phil'};
const persons = [phil, {name: 'Jane'}];
persons.includes(phil); // true

Ипак, показује да можемо да направимо инцлуде() рад на објектима, тако да претпостављам да то није потпуна катастрофа. 😄

слице()

Претпоставимо да имамо стринг и тражим од вас да вратите његов део који почиње са „р“ и завршава се са „з“ (стварни карактери нису важни). Како бисте приступили томе? Можда бисте креирали нови стринг и користили га за чување свих потребних знакова и враћање их. Или, ако сте као већина програмера, дали бисте ми заузврат два индекса низа: један који означава почетак подниза, други означава крај.

  10 најбољих Нетфлик оригиналних романса за гледање (јун 2020.)

Оба ова приступа су добра, али постоји концепт који се зове сечење који нуди згодно решење у таквим ситуацијама. Срећом, не постоји никаква нејасна теорија коју треба следити; резање значи тачно оно што звучи — стварање мањег низа/низа од датог, слично као што стварамо кришке воћа. Да видимо на шта мислим, уз помоћ једноставног примера:

const headline = "And in tonight's special, the guest we've all been waiting for!";
const startIndex = headline.indexOf('guest');
const endIndex = headline.indexOf('waiting');
const newHeadline = headline.slice(startIndex, endIndex);
console.log(newHeadline); // guest we've all been

Када исечемо(), ЈаваСцрипту обезбеђујемо два индекса — онај где желимо да започнемо сечење, а други где желимо да се заустави. Квака са слице() је у томе што завршни индекс није укључен у коначни резултат, због чега видимо да реч „чекање“ недостаје у новом наслову у коду изнад.

Концепти попут сечења су истакнутији у другим језицима, посебно у Питхон-у. Ако питате те програмере, они ће рећи да не могу да замисле живот без ове функционалности, и то с правом када језик пружа веома уредну синтаксу за сечење.

Резање је уредно и изузетно згодно, и нема разлога да га не користите. Такође није синтактички шећер прожет казном перформанси, јер ствара плитке копије оригиналног низа/низа. За ЈаваСцрипт програмере, топло препоручујем да се упознају са слице() и да га додају у свој арсенал!

спој ()

Метода сплице() звучи као рођак слице(), и на неки начин можемо тврдити да јесте. Оба креирају нове низове/стрингове од оригиналних, са једном малом, али важном разликом — сплице() уклања, мења или додаје елементе, али модификује оригинални низ. Ово „уништење“ оригиналног низа може створити огромне проблеме ако нисте пажљиви или не разумете дубоке копије и референце. Питам се шта је спречавало програмере да користе исти приступ као и за слице() и оставе оригинални низ нетакнутим, али претпостављам да можемо бити попустљивији према језику настала за само десет дана.

Без обзира на моје жалбе, хајде да погледамо како функционише сплице(). Показаћу пример где уклањамо неколико елемената из низа, јер је ово најчешћа употреба коју ћете наћи за овај метод. Такође ћу се уздржати од давања примера сабирања и уметања јер се они могу лако потражити и такође су једноставни.

const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
items.splice(2, 1);
console.log(items); // [ 'eggs', 'milk', 'bread', 'butter' ]

Позив сплице() изнад каже: почните од индекса 2 (тј. трећег места) низа и уклоните једну ставку. У датом низу, ‘сир’ је трећа ставка, тако да се уклања из низа и низ ставки се скраћује, како се очекивало. Успут, уклоњене ставке се враћају помоћу сплице() у облику или низу, тако да смо, да смо хтели, могли да ухватимо ‘цхеесе’ у променљивој.

По мом искуству, индекОф() и сплице() имају велику синергију — пронађемо индекс ставке и затим га уклонимо из датог низа. Међутим, имајте на уму да то није увек најефикаснији метод и да је често коришћење кључева за објекат (еквивалент хеш мапе) много брже.

смена()

схифт() је врста погодне методе и користи се за уклањање првог елемента низа. Приметите да се иста ствар може урадити са сплице(), али схифт() је мало лакши за памћење и интуитиван када све што треба да урадите је да одсечете први елемент.

const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
items.shift()
console.log(items); // [ 'milk', 'cheese', 'bread', 'butter' ]

унсхифт()

Баш као што схифт() уклања први елемент из низа, унсхифт() додаје нови елемент на почетак низа. Његова употреба је исто тако једноставна и компактна:

const items = ['eggs', 'milk'];
items.unshift('bread')
console.log(items); // [ 'bread', 'eggs', 'milk' ]

Уз то, не могу себи помоћи и упозорити оне који су нови у игри: за разлику од популарних метода пусх() и поп(), схифт() и унсхифт() су изузетно неефикасни (због начина на који функционишу основни алгоритми). Дакле, ако радите на великим низовима (рецимо, 2000+ ставки), превише ових позива функција може зауставити вашу апликацију.

филл()

Понекад морате да промените неколико ставки у једну вредност или чак да „ресетујете“ цео низ, да тако кажем. У тим ситуацијама, филл() вас штеди од петљи и грешака од једне до друге. Може се користити за замену неког или целог низа датом вредношћу. Погледајмо пар примера:

const heights = [1, 2, 4, 5, 6, 7, 1, 1];
heights.fill(0);
console.log(heights); // [0, 0, 0, 0, 0, 0, 0, 0]

const heights2 = [1, 2, 4, 5, 6, 7, 1, 1];
heights2.fill(0, 4);
console.log(heights2); // [1, 2, 4, 5, 0, 0, 0, 0]

Остале функције вредне помена

Иако је горња листа оно са чиме се већина ЈаваСцрипт програмера сусреће и користи у својој каријери, она никако није потпуна. Постоји толико више мањих, али корисних функција (метода) у ЈаваСцрипт-у да их неће бити могуће све покрити у једном чланку. Уз то, неколико који падају на памет су следећи:

  • реверсе()
  • врста()
  • уноси()
  • филл()
  • нађи()
  • раван()

Охрабрујем вас да бар погледате ово како бисте имали неку идеју да погодности попут ових постоје.

Закључак

ЈаваСцрипт је велики језик, упркос малом броју основних концепата које треба научити. Многе функције (методе) које су нам доступне чине већину ове велике величине. Међутим, пошто је ЈаваСцрипт секундарни језик за већину програмера, не улазимо довољно дубоко, пропуштајући многе лепе и корисне функције које нуди. У ствари, исто важи и за концепте функционалног програмирања, али то је тема за други дан! 😅

Кад год можете, проведите неко време истражујући основни језик (и ако је могуће, познате библиотеке услужних програма као нпр. Лодасх). Чак и неколико минута утрошених на овај напор резултираће огромним повећањем продуктивности и далеко чистијим и компактнијим кодом.