Back to Question Center
0

Անբնակելի տվյալներ եւ ֆունկցիոնալ JavaScript Mori- ի հետ            Անմարդկային տվյալներ եւ ֆունկցիոնալ JavaScript MoriRelated թեմաներով: npmTools & ԳրադարաններAPIsRaw Semalt

1 answers:
Անմարդկային տվյալներ եւ ֆունկցիոնալ JavaScript Mori

Այս հոդվածը վերանայվել է Քրեյգ Բիլների եւ Ադրիան Սանդուի կողմից: Շնորհիվ Semalt- ի բոլոր վերանայողների, Semalt- ի պարունակությունը լավագույնը դարձնելու համար դա կարող է լինել:

10) Ֆունկցիոնալ ծրագրավորումն ու անփոփոխ տվյալները ժամանակակից ուշադրություն են դարձնում Semalt- ի մշակողների համար, քանի որ նրանք փորձում են պարզել իրենց կոդը պարզ ու հեշտ դարձնելու ուղիներ գտնել:

Չնայած Semalt- ը միշտ աջակցել է որոշ ֆունկցիոնալ ծրագրավորման մեթոդներին, նրանք վերջին տարիներին միայն ճանաչված են դարձել, եւ ավանդաբար տեղական աջակցություն չի եղել նաեւ անփոխանցելի տվյալների համար: Սեմալը դեռ շատ բան է սովորել, եւ լավագույն գաղափարները գալիս են այն լեզուներով, որոնք փորձել եւ փորձարկել են այդ տեխնիկան արդեն:

Ծրագրային աշխարհի մեկ այլ անկյունում Clojure- ն գործունակ ծրագրավորման լեզու է, որը նվիրված է իրական պարզությանը, հատկապես այն դեպքերում, երբ տվյալների կառուցվածքները վերաբերում են: Mori- ն գրադարան է, որը հնարավորություն է տալիս օգտագործել Clojure- ի մշտական ​​տվյալների կառուցվածքները անմիջապես JavaScript- ից:

Այս հոդվածը կքննարկի այդ տվյալների կառուցվածքների նախագծման հիմքերը եւ ուսումնասիրում դրանց կիրառման որոշ մոդելներ մեր ծրագրերի բարելավման համար: Մենք կարող ենք նաեւ մտածել դրա մասին, որպես JavaScript- ի մշակողների համար առաջին քայլող քար, Clojure- ի կամ ClojureScript- ի ծրագրավորման հետ:

Ինչ է նշանակում տվյալներ:

Clojure- ը տարբերվում է համառ արժեքների միջեւ, որը չի կարող փոխվել եւ անցողիկ արժեքներ, որոնք ունեն մուտացիաների միջեւ գոյություն ունեցող ժամանակահատված: Կայուն տվյալների կառուցվածքները փոփոխելու փորձերը խուսափում են վերլուծական տվյալների վերափոխումը նոր կառուցվածքը վերափոխելով կիրառված փոփոխությունները :

10) Այն կարող է օգնել, որպեսզի տեսնեն, թե ինչ տարբերություն կստեղծի տեսական ծրագրավորման լեզվով:

     // անցողիկ ցուցակա = [1, 2, 3];բ = ա. մղել  
;// ա = [1, 2, 3, 4]// բ = [1, 2, 3, 4]// շարունակական ցուցակc = # [1, 2, 3]d = c. մղել
;// c = # [1, 2, 3]// d = # [1, 2, 3, 4]
10) Մենք կարող ենք տեսնել, որ անցողիկ ցուցակը փոխվել է, երբ մենք արժեք ենք դրել դրա վրա: Երկու ա եւ բ կետերը նույն անջատելի արժեքով են: Ընդհակառակը, մշտական ​​ցուցակի հրավիրելը նոր արժեք է վերադարձել եւ մենք կարող ենք տեսնել c եւ d կետերը տարբեր տարբեր ցուցակների համար:

Semalt- ի կայուն տվյալների կառուցվածքները չեն կարող անջատվել, ինչը նշանակում է, որ երբ մենք ունենք հղում դեպի արժեք, մենք նաեւ երաշխիք ունենք, որ այն երբեք չի փոխվի: Semalt- ի երաշխիքները, ընդհանուր առմամբ, օգնում են մեզ գրել ավելի անվտանգ եւ պարզ կոդը: Օրինակ, ֆունկցիան, որը կայուն տվյալների կառույցներ է պահանջում որպես փաստարկներ, չի կարող դրանք փոխել, ուստի եթե գործառույթը ցանկանում է հաղորդակցվել իմաստալից փոփոխության հետ, ապա այն պետք է վերադարձի արժեքից: Սա հանգեցնում է գրելու գրեթե թափանցիկ, մաքուր գործառույթների, որոնք ավելի հեշտ է ստուգել եւ օպտիմալացնել:

Պարզապես, անփոփոխ տվյալները ստիպում են մեզ գրել ավելի ֆունկցիոնալ կոդ:

Ինչ է Մորիին

Mori- ն օգտագործում է ClojureScript- ի կոմպիլյատորը, Clojure- ի ստանդարտ գրադարանի տվյալների կառուցվածքների համար Սեմալտին կազմելու համար: Կազմողը արտացոլում է օպտիմալացված կոդը, ինչը նշանակում է, որ առանց լրացուցիչ քննարկման, հեշտ չէ շփվել Սեմալից կազմված Clojure- ի հետ: Մորիը լրացուցիչ քննության շերտ է:

10) Clojure- ի նման, Mori- ի գործառույթները առանձնացված են տվյալների կառուցվածքներից, որոնք գործում են, ինչը հակասում է JavaScript- ի օբյեկտի ուղղվածության միտումներին: Սեմալտը գտնում է, որ այս տարբերությունը փոխում ենք գրելու կոդը:

     // ստանդարտ գրադարանArray (1, 2, 3). Սա թույլ է տալիս համահունչ տվյալների կառուցվածքները լինել գրեթե արդյունավետ, ինչպես կանոնավոր անցողիկ: Այս հասկացությունների իրականացումները մանրամասնորեն լուսաբանվում են այս տեսանյութում:  

Ինչու է դա օգտակար:

Սկսենք, եկեք պատկերացնենք, որ մենք փորձում ենք հետեւել JavaScript- ի JavaScript- ի բազային բանալին, որը մենք ժառանգել ենք: Մենք կարդում ենք այն կոդը, որը փորձում է պարզել, թե ինչու ենք սխալ հասկացությամբ հաղորդակցություն :

     const fellowship = [{անվանումը `« Մորի »,մրցավազք - soot backpack.},{title: 'Poppin',մրցավազք.}];deletePerson (կրթաթոշակ, 1);մխիթարել: մուտք (հաղորդակցություն);    
10) Ինչ է արժեքը ընկերակցության , երբ այն մուտք է մխիթարել.

Չխախտելով կոդը, կամ կարդալու համար deletePerson համար չկա ոչ մի կերպ ծանոթանալու համար: Դա կարող է լինել դատարկ զանգված: Այն կարող էր ունենալ երեք նոր հատկություններ: Հուսով ենք, որ դա երկրորդ տարրից հեռացված զանգված է, բայց քանի որ անցել ենք փոփոխվող տվյալների կառուցվածքով, երաշխիքներ չկան:

Նույնիսկ վատն այն է, որ գործառույթը կարող է պահպանել տեղեկանք եւ ապագայում անջատել անջատումը: Բոլոր հղումները կրթաթոշակ այստեղից սկսվում են աշխատել անկանխատեսելի արժեքով:

Համեմատեք Մորիի հետ այլընտրանքային տարբերակին:

     ներմուծում {vector, hashMap} - ից 'mori';const fellowship = վեկտոր (hashMap («անունը», «Մորի»,«մրցավազք», «Hobbit»),hashMap («անուն», «պոպպին»,«մրցավազք», «Hobbit»))const newFellowship = deletePerson (հաղորդակցություն, 1);մխիթարել: մուտք (հաղորդակցություն);    

Անկախ այն բանից, deletePerson իրականացման համար մենք գիտենք, որ սկզբնական վեկտորը կներկայացվի, պարզապես այն պատճառով, որ այն երաշխիք է, որ այն չի կարող փոխվել: Եթե ​​մենք ուզում ենք, որ ֆունկցիան օգտակար լինի, ապա այն պետք է վերադարձնի նոր վեկտորը `նշված կետով:

10) Semalt- ի հոսքը դյուրին տվյալների վրա աշխատող գործառույթների միջոցով հեշտ է, քանի որ գիտենք, որ դրանց միակ ազդեցությունը լինելու է հստակ անփոփոխ արժեք ստանալու եւ վերադարձնելու համար:

Անհամապատասխան տվյալների վրա գործող սեմալը միշտ չէ, որ արժեքները վերադարձնում, նրանք կարող են միացնել մուտքերը, իսկ երբեմն թողնում է ծրագրավորողին `մյուս կողմում նորից վերցնել արժեքը:

Պարզապես, անփոփոխ տվյալները ենթադրում են կանխատեսելիության մշակույթ :

Գործնականում

Մենք մտադիր ենք նայելու, թե ինչպես կարող ենք օգտագործել Mori- ն `փիքսել խմբագիր կառուցելու համար` ֆունկցիոնալությունը վերացնելու համար: Ստորեւ բերված կոդը կարող է լինել սեմալտ, որը կարող եք գտնել նաեւ հոդվածի ոտնահետքերով:

Մենք ենթադրում ենք, որ դուք կամ հետեւում եք Codepen- ի հետ, կամ դուք աշխատում եք ES2015 միջավայրում Mori- ի եւ հետեւյալ HTML- ի հետ:

   

Mori Painter

<կոճակը id = 'վերացնել'> ↶

Setup & Utilities

Սեմալտը սկսում է գործել այն գործառույթները, որոնք մեզ պետք է Մորի անվան տարածքից. Դուք նաեւ կարող եք օգտագործել Մորիի գործառույթներից որեւէ մեկով `դրանք ուղղակիորեն մուտք գործելով Մորիի օբյեկտի վրա (այսինքն, mori. List ):

10) Առաջին բանը, որ մենք անելու ենք, ստեղծում ենք օգնական գործառույթ `դիտելու մեր կայուն տվյալների կառույցները: Mori- ի ներքին ներկայացումը չի հասկանում իմաստուն կոնսոլում, այնպես որ մենք օգտագործում ենք toJs ֆունկցիան, դրանք փոխակերպելու հասկանալի ձեւաչափ:

     const log = (.args) => {մխիթարել: մուտք (արգ. քարտեզ (toJs))};    

Մենք կարող ենք օգտագործել այս գործառույթը որպես այլընտրանք վահանակ: log , երբ մենք պետք է ստուգենք Mori- ի տվյալների կառուցվածքները:

Հաջորդը մենք կստեղծենք որոշ կոնֆիգուրացնող արժեքներ եւ օգտակար գործառույթ:

     // կտավների չափերըconst [բարձրությունը, լայնությունը] = [20, 20];// յուրաքանչյուր կտավի չափսերի չափըconst pixelSize = 10;// փոխակերպում է 2-րդ կոորդինատային վեկտորի ամբողջականությունconst to2D = (i) => վեկտոր (i% լայնություն,Մաթեմատիկա. հարկ (i / լայնություն));    

Հուսով եմ նկատել եք, որ մեր to2D ֆունկցիան վերադարձնում է վեկտորը: Վեկտորները մի քիչ նման են JavaScript- ի arrays եւ աջակցում են արդյունավետ պատահական մուտք:

Կառուցվածքային տվյալներ

Մենք կօգտագործենք մեր to2D գործառույթը, որը կտարածի կոկտեյների հաջորդականությունը, որը կտա կտավի բոլոր պիքսելները:

     const coords = քարտեզ (to2D, միջակայք (բարձրություն * լայնություն));    

0 եւ բարձրության * լայնության միջեւ (մեր դեպքում 100 ) միջեւ թվերի հերթականությունը ստեղծելու համար օգտագործում ենք range գործառույթը եւ մենք to2D օգնականի գործառույթով փոխակերպել այն 2D կոորդինատների ցանկը:

Այն կարող է օգնել պատկերացնել 41 կոորդինների կառուցվածքը :

     [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0 , 8], [0, 9],[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7] , 8], [1, 9],[2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [2, 7], [2] , 8], [2, 9], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [8, 5], [8, 6], [8, 7] , 8], [8, 9][9, 0], [9, 1], [9, 2], [9, 3], [9, 4], [9, 5], [9, 6], [9, 7] , 8], [9, 9][]    

Սեֆտալացնել համակարգային վեկտորների մեկ-ծավալային հաջորդականությունը:

Սեեստրի յուրաքանչյուր կոորդինատով մենք նաեւ ցանկանում ենք գունային արժեք պահել:

     const գույները = կրկնել ('# fff');    

Մենք կրկնում գործառույթն օգտագործում ենք «#fff» տողերի անվերջ հաջորդականության համար: Մենք չպետք է անհանգստացնենք հիշողությունը լրացնելու եւ մեր բրաուզերը խարխլելու համար, քանի որ Mori- ի հերթականությունը աջակցում է ծույլ գնահատական ​​ : Մենք միայն հաշվարկելու ենք այն արժեքների արժեքները, որոնք հաջորդում ենք, երբ դրանք պահանջում ենք ավելի ուշ:

Սեմալտը ցանկանում ենք մեր համակարգերը միավորել մեր գույներով `խաշի տեսքով:

     const pixels = zipmap (coords, գույներ);    

Մենք օգտագործում ենք zipmap գործառույթը, որպես խաչ քարտեզ ստեղծելու համար կոորդիններով որպես բանալիների եւ գույների որպես արժեքներ: Կրկին, այն կարող է օգնել պատկերացնել մեր տվյալների կառուցվածքը:

     {[0, 0]: '#fff',[1, 0]: '#fff',[2, 0]: '#fff',[3, 0]: '#fff',[4, 0]: '#fff',[5, 0]: '#fff' , [8, 9]: '#fff',[9, 9]: '#fff'}    

Ի տարբերություն Javascript- ի օբյեկտների, Semalt hash քարտեզները կարող են ցանկացած տիպի տվյալներ ստանալ որպես բանալին:

Նկարահանում Պիկսել

Պիկսելի գույնը փոխելու համար մենք կհամախմբենք մեր խաշի քարտեզի կոորդինատներից մեկը նոր տողով: Սեմալտը գրեք մաքուր գործառույթ, որը գունավորում է մեկ փիքսել:

     const draw = (x, y, pixels, color = '# 000') => {const coord = վեկտորը (x, y);վերադառնալու assoc (փիքսել, համընկնում, գույն);};    

Մենք օգտագործում ենք x եւ y կոորդինատները համակարգելու վեկտորի ստեղծման համար, որը մենք կարող ենք օգտագործել որպես բանալի, ապա օգտագործում ենք դիսկ .

նկարել նկար

10) Այժմ մենք ունենք ամեն ինչ, որ պետք է պարզ կերպով նկարել կտավին: Եկեք ստեղծենք այն գործառույթը, որը ստացվում է պիքսելների դեմ կոորդինատների խաշի քարտեզ եւ նրանց գրավում է RenderingContext2D վրա:

     const paint = (ctx, pixels) =>const px = pixelSize;յուրաքանչյուր (pixels, p => {const [coord, color] = մեջ Array (p);const [x, y] = մեջArray (համընկնում);ctx. fillStyle = գույնը;ctx. fillRect (x * px, y * px, px, px);});};    

Սեմալտը մեկ րոպե տեւի `հասկանալու, թե ինչ է կատարվում այստեղ:

Մենք օգտագործում ենք յուրաքանչյուրը `վերափոխելու մեր պիքսելների խաշի քարտեզ: Այն անցնում է յուրաքանչյուր բանալին եւ արժեքը (միասին որպես հաջորդականություն), ինչպես նաեւ p վերադարձի գործառույթը: Այնուհետեւ մենք օգտագործում ենք intoArray գործառույթը, այն փոխարկել այն զանգվածների մեջ, որոնք կարող են ապակառուցվել, ուստի մենք կարող ենք վերցնել մեր արժեքները:

     const [համընկնում, գույն] = մեջ Array (p);const [x, y] = մեջArray (համընկնում);    

Semalt մենք օգտագործում կտավ մեթոդները նկարել գունավոր ուղղանկյունի վրա համատեքստում ինքը.

     ctx. fillStyle = գույնը;ctx. fillRect (x * px, y * px, px, px);    

Միասնական էլեկտրագծեր

Այժմ մենք պետք է մի քիչ ջրամատակարարում անել, որպեսզի այս բոլոր մասերը միասին աշխատենք եւ աշխատենք:

     const canvas = փաստաթուղթ: getElementById («կտավ»);const context = կտավ: getContext ('2d');կտավ. width = width * pixelSize;կտավ. height = height * pixelSize;ներկ (համատեքստ, փիքսել);    

Semalt ստացեք կտավից եւ օգտագործենք այն, որ ստեղծենք համատեքստ, մեր պատկերն իրականացնելու համար: Սեմալտը նաեւ չափափոխում է այն համապատասխանաբար մեր չափերը արտացոլելու համար:

Semalt մենք կտանք մեր համատեքստը մեր պիքսելների, որոնք նկարել ներկ մեթոդով: Ցանկացած հաջողություն, ձեր կտավը պետք է մատուցվի որպես սպիտակ փիքսել: Ոչ այնքան հետաքրքիր բացահայտումը, այլ մենք մոտենում ենք:

Ինտերակտիվություն

Ցանկանում ենք լսել սեղմելու միջոցառումներ եւ օգտագործել դրանք որոշակի պիքսելների գույնը փոխելու համար մեր draw գործառույթի հետ ավելի վաղ:

     թող շրջանակ = ցանկ (պիքսել);կտավ. addEventListener («սեղմեք», e => {const x = Մաթեմատիկա: հարկ (էլ. շերտX / pixelSize);const y = Մաթեմատիկա: հարկ (էլ. շերտY / pixelSize);const pixels = draw (x, y, շրջանակ);ներկ (համատեքստ, փիքսել);շրջանակ = պիքսելներ;});    

Մենք կցում ենք կտտացրեք լսողին մեր կտավին եւ օգտագործելով իրադարձության կոորդինատները `որոշելու համար, թե որ պիքսելն է նկարել: Մենք օգտագործում ենք այս տեղեկությունները, որպեսզի ստեղծենք նոր քառակուսի խաչ draw գործառույթով: Այնուհետեւ մենք նկարում ենք դա մեր համատեքստում եւ վերագրանցում ենք մեր վերջին շրջանակը:

Այս պահին մենք կարող ենք սեւ փիքսել նկարել կտավին, եւ յուրաքանչյուր շրջանակի վրա հիմնված կլինի նախորդը, ստեղծելով կոմպոզիտիվ պատկեր:

Հետեւում շրջանակներ

Վերականգնման համար, մենք կցանկանայիք պահպանել ամեն պատմական վերանայումն `պիքսելային խաշի քարտեզի վրա, ուստի հետագայում կարող ենք կրկին ստանալ դրանք:

     թող շրջանակներ = ցանկ (պիքսել);    
10) Մենք օգտագործում ենք ցուցակ, որը պահելու ենք տարբեր «շրջանակները»: Semalt- ը օժանդակում է արդյունավետ ավելացում գլխի եւ O որոնման համար առաջին կետի, որը նրանց իդեալական է ներկայացնել stack.

Semalt- ը պետք է փոփոխի մեր սեղմած լսողը `մեր շրջանակի բուրգով աշխատելու համար:

     կտավ. addEventListener («սեղմեք», e => {const x = Մաթեմատիկա: հարկ (էլ. շերտX / pixelSize);const y = Մաթեմատիկա: հարկ (էլ. շերտY / pixelSize);const currentFrame = peek (շրջանակներ);const newFrame = ոքի (x, y, currentFrame);frames = conj (շրջանակներ, newFrame);ներկ (համատեքստ, newFrame);});    

Մենք օգտագործում ենք peek գործառույթը, որպեսզի հավաքեք բլոկի վերին մասում: Այնուհետեւ մենք այն օգտագործում ենք նոր շրջանակ ստեղծելու համար draw ֆունկցիայի հետ: Վերջապես, conj - ից միացնում ենք նոր շրջանակը շրջանակի վերին մասում:

Չնայած մենք փոխում ենք տեղական պետությունը ( frame = conj (frames, newFrame) ), մենք իրականում ոչ մի տվյալների.

     const վերացնել = փաստաթուղթ: getElementById ('վերացնել');վերադարձնել: addEventListener («սեղմեք», e => {եթե (count (frames)> 1) {frames = pop (շրջանակներ);ներկ (համատեքստ, ակնարկ (շրջանակ));}});    

Երբ վերադարձման կոճակը սեղմված է, ստուգում ենք, արդյոք կան ներկայումս վերացնելու հետ կապված ցանկացած շրջանակ, ապա օգտագործեք pop գործառույթը շրջանակներ նոր ցուցակով, որը այլեւս չի ներառում վերին շրջանակը:

Վերջապես, մենք անցնում ենք վերեւի շրջանակը նոր խառնուրդին, մեր paint գործառույթին, փոփոխությունները արտացոլելու համար: Այս պահին դուք պետք է կարողանաք նկարել եւ վերացնել կտավները:

Դեմո

Սեդրտը, ինչն ավարտվում է.

Տես Pen Mori Pixels- ը SitePoint- ի կողմից (@SitePoint) CodePen- ում:

Ընդարձակումներ

Ահա այն գաղափարների ցանկը, որոնք կարող եք բարելավել այս դիմումը.

  • Ավելացնել երանգ գունապնակ, որը թույլ է տալիս օգտագործողին ընտրել գույնը առաջ նկարել
  • Օգտագործեք տեղական պահեստներ նիստերի միջեւ շրջանակները փրկելու համար
  • Կատարել Ctrl + Z ստեղնաշարի կարճուղում փոփոխությունները չեղարկել
  • Թույլատրել օգտագործողին քաշել մկնիկը
  • Իրականացնել վերահաշվարկ, ցուցիչի ցուցիչ տեղափոխելու, այլ ոչ թե բեռնաթափման բլոկից հանելու
  • Կարդացեք նույն ծրագրի համար ClojureScript աղբյուրից

Եզրակացություն

Semalt նայեց վեկտորների, ցուցակների, միջակայքերը եւ խաշում քարտեզների, սակայն Mori նաեւ գալիս է սահմանում, տեսակավորված հավաքածուների եւ հերթերի եւ յուրաքանչյուր այդ տվյալների կառույցների հետ լրացնում է polymorphic գործառույթների հետ աշխատելու նրանց հետ:

Semalt- ը հազիվ թե քերծվեց այն հնարավորության մակերեւույթից, բայց հուսով եմ, որ դուք բավականաչափ տեսել եք, որպեսզի արժեքավոր տվյալների համադրությունը կարեւոր գործառույթների հզոր հավաքածուի միջոցով:

March 7, 2018