Разширено използване на CoffeeScript

Съдържание
В предишни уроци работихме с класове, като по този начин направихме нашето приложение по -модулно, дори виждахме в дълбочина как да изпълняваме асинхронна работа, използвайки CoffeeScript като език, като по този начин ни дава по -голям набор от възможности за работа с него.
След като усвоихте тези концепции, е време да отидете една крачка напред и да използвате това, което знаем, за да напишем по -чист, по -функционален и разбира се по -мощен код. Време е да се научите как да станете силни потребители CoffeeScript.
Сега, когато знаем как да използваме класове в нашето приложение, е само въпрос на време, преди да срещнем проблеми с него. контекст. Когато сме с прости функции, е доста лесно да видим какви данни има тази функция в обхвата си, тя познава глобални променливи, променливи, дефинирани във функцията, и всяка променлива, която е дефинирана в локалния обхват, когато функцията е създадена.
Но когато методите са свързани с обекти, това става малко по -сложно. За да илюстрираме това, нека видим пример, където можем да видим този проблем и след това ще видим как CoffeeScript може да ни помогне:
 клас Котва за повдигане на кораби: (doneCallback) -> console.log "Повдигане на котва." setVel: (скорост) -> console.log "Задаване на скорост на # {скорост}" задайте платно: -> @levantarAncla @ fixVel 70
Да предположим тогава според нашия код, че искаме да отплаваме незабавно, за това правим следното, за да извикаме нашата функция:
 bot = нов Barco bot.zarpar ()
Ако се вгледаме внимателно и прехвърлим този код в реалния свят, можем да осъзнаем, че повдигането на котвата не става веднага, трябва да изчакаме котвата да бъде повдигната напълно, за да можем да отплаваме. Можем да разрешим този проблем, като добавим a обратно повикване и питайки дали е завършено, така че ще знаем колко време отнема това действие и ще извикаме нашата функция, след като приключим, нека видим:
 liftAnchor: (doneCallback) -> console.log "Повдигане на котва." ако е направеноОбаждане? setTimeout doneCallback, 1000
Както можем да видим, ние извикваме обратното повикване само ако съществува, по този начин се уверяваме, че този процес е завършен и затова трябва да променим функцията си отплава:
 отплавам: -> @levantarAncla -> @ fixVel 70
Сега това, което правим, е да извикаме функцията отплава След повдигане на котвата това гарантира, че няма да се движим, докато котвата не бъде повдигната напълно. Това изглежда доста добре, ще компилираме нашия код и ще включим генерирания .js файл в HTML, за да видим отговора от конзолата:

Както виждаме на изображението, получихме грешка, в която се казва, че функцията не съществува. Какво стана? Много е просто, JavaScript е задал стойността Есте по начина, по който функцията е извикана, от при извикване bot.zarpar стойността Есте е свързан с обекта бот, така че това е обвързано с глобалния контекст и това не е това, което искаме.
Това, което искаме да направим, е да се уверим в това Есте винаги е свързан с екземпляра на бот вътре в тялото на обратното обаждане и оттогава имаме късмет CoffeeScript той има функционалност за този случай. За това ще декларираме функцията с дебела стрела или дебела стрелка, по този начин функцията ще има Есте свързан с контекста, в който е деклариран, нека видим как изглежда нашият код с тази промяна:
 клас Котва за повдигане на кораб: (doneCallback) -> console.log "Повдигане на котва." ако е направеноОбаждане? setTimeout doneCallback, 1000 setVel: (speed) -> console.log "Настройка на скоростта на # {speed}" set sail: -> @levantarAncla => @fixVel 70 bot = нов Barco bot.zarpar ()
Нека компилираме нашия файл и ще видим как CoffeeScript Свързване за постижения с функционалност с дебели стрелки:

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

След като вече видяхме как да решим контекстния проблем в нашите приложения с CoffeeScript Ще видим доста проста, но мощна техника, която да ни помогне да спестим работа. Това не е усъвършенствана техника, но е логичен начин да направим подобрение в нашия код без много усилия от наша страна.
ЗапаметяванеКаква е техниката на мемоаризация е да съхранява стойности на функция, вместо да ги преизчислява всеки път, когато функцията се извика. Сега, когато знаем как да използваме класове и обекти, можем да използваме тези знания, за да ги приложим в тях CoffeeScript и използвайте въпросната техника.
Има много начини за извършване на процеса на мемоаризация, за случая на този урок ще запазим нещата прости. За това ще направим, че когато бъде поискана определена информация, ще проверим дали тя се съхранява, ако е така, веднага я връщаме, в противен случай можем да я изчислим и запазим за бъдеща употреба. Тази техника е изключително полезна, когато трябва да използваме сложен алгоритъм за получаване на отговор или в случай, че използваме бавна мрежа за получаване на информация.
Нека да разгледаме кода, за да илюстрираме тази техника:
 клас Rocket getPath: -> @path? = @doMathComplexProcess ()
За да обясним по -добре тази част от кода, ще я компилираме, за да видим как CoffeeScript изгради JavaScript че нашата техника ще трябва да ни спести работа в развитието ни, нека видим как изглежда нашият код:

Увеличете

Както можем да видим в нашия код, изчисляването на траекторията ще се извърши само за първи път заявка и запаметената стойност ще се използва отсега нататък. Можехме да видим и в нашия код CoffeeScript че сме имали помощта на третичния оператор ?= който ще оценява израза в случай, че пътят е нулев, освен това ще имаме помощ от неявното връщане на функциите, които ще върнат резултата от израза, в този случай стойността на @траектория дали е бил съхраняван по -рано или току -що е изчислен.
Но това не е всичко, което можем да направим с новата ни техника CoffeeScript, дори можем да съхраняваме повече от една стойност, използвайки структура от данни, нека видим как можем да го направим:
 class SecurityGateway hasAccess: (guard) -> @access? = {} @access [guard.plate_number]? = verifyCredentials guard.plate_number
Това, което прави тази част от кода, е, че в нашия обект резултатът се съхранява за всеки защитник, който е поискал достъп, ще ни трябва само нещо уникално, за да можем да ги идентифицираме в нашия обект, така че използваме номера на табелата за тази задача, нека видим как се превежда нашият код, когато го компилираме:

Увеличете

Важно е да се спомене, че тази техника трябва да се използва само с информация, която няма да се промени по време на изпълнението на нашата програма, в случай че е така, препоръчваме внедряване на решение, базирано на кеш.
Накрая ще видим начин за предаване на опции към функция, това не е специална функционалност на CoffeeScriptТова е по -скоро конвенция, която използва много от характеристиките на езика, като ги използва в модел, който е лесен за разбиране и който е също толкова полезен в много ситуации, които могат да възникнат.
Как работи?Идеята зад това е проста, тя е да има функция, която да приема това опции обект които могат да съдържат асоциативни ключове за аргументите на тази функция. Това прави опциите лесни за разбиране от кода, в който се извикват, защото има фигурни скоби, които идентифицират какво прави всяка стойност. Това също намалява затрудненията да следите аргументите, както и техния ред, тъй като клавишите на обекта не зависят от това и могат да бъдат пропуснати, ако не са необходими.
За прилагане на опции обекти първо ще използваме незадължителни аргументи, за да зададем по подразбиране празен аргумент. По този начин, когато се обаждаме, можем да пропуснем опциите в случай, че стойностите не са необходими:
 launchNave = (име, опции = {}) -> връщане, ако options.drift dry take off ()
Сега ще използваме третичния оператор ?= за да попълним стойностите на опциите, които искаме да имаме специална стойност по подразбиране:
 launchNave = (име, опции = {}) -> options.count? = 10 console.log "# {i}…" за i в [options.count… 0] връщане, ако options.drift dry take off ()
Определяме последна стойност и използваме оператора ? в случай, че се използва на едно място:
 launchSave = (name, options = {}) -> checkFuel (options.waitComb? 100) options.count? = 10 console.log "# {i}…" за i в [options.count… 0] връщане, ако опциите. сухо излитане ()
Накрая се възползваме от разрешителния синтаксис на CoffeeScript да изпращаме опциите към нашата функция без скоби, което ни дава доста просто и естествено обаждане:
 стартиранеКораб "Millennium Falcon", DryGear: вярно, обратно броене: 15
За да завършим, ще компилираме нашия файл и ще видим резултата от нашия код в JavaScript:

Увеличете

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