Javascript, functie niet in loop, maar hoe wel

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Guillome
  • Registratie: Januari 2001
  • Niet online
Beste,

Ik heb al langer dit vraagstuk en heb er eigenlijk nog geen goede oplossing voor gevonden.

Situatie:
JavaScript:
1
2
3
4
5
let val = 10;

myArray.forEach( row => {
    let item = row.data.find( rowItem => rowItem.key === val);
});


Dit werkt, maar het is niet netjes om een functie in een loop aan te maken.
Dus mij lijkt zoiets beter:
JavaScript:
1
2
3
4
5
6
let val = 10;
let delegateFindItem = rowItem => rowItem.key === val;

myArray.forEach( row => {
    let item = row.data.find( delegateFindItem );
});


Maar ik weet niet hoe ik op de juiste wijze de variable val in de functie krijg.
Moet het met bind, is dat de beste oplossing?
JavaScript:
1
2
3
4
5
6
let val = 10;
let delegateFindItem = (val, rowItem) => rowItem.key === val;

myArray.forEach( row => {
    let item = row.data.find( delegateFindItem.bind( this, val) );
});


Je kan ook de delegate met () aanroepen:
JavaScript:
1
2
3
4
5
6
let val = 10;
let delegateFindItem = val => rowItem => rowItem.key === val;

myArray.forEach( row => {
    let item = row.data.find( delegateFindItem(val) );
});

Maar dan maak je nog steeds een functie in een loop volgens mij.

Wat is de beste manier?

If then else matters! - I5 12600KF, Asus Tuf GT501, Asus Tuf OC 3080, Asus Tuf Gaming H670 Pro, 48GB, Corsair RM850X PSU, SN850 1TB, Arctic Liquid Freezer 280, ASUS RT-AX1800U router

Beste antwoord (via Guillome op 11-04-2018 18:23)


  • frankmulder
  • Registratie: Januari 2010
  • Laatst online: 06-10 21:13
Als het je er echt om gaat dat je die waarschuwing wegwerkt, kun je eens kijken op StackOverflow (bijvoorbeeld https://stackoverflow.com...ons-within-a-loop#3038555).

Als je gewoon je code wilt verbeteren (en dat lijkt me een betere instelling), dan zou ik zoiets doen:
JavaScript:
1
const items = [].concat(...myArray.map(row => row.data)).filter(item => item.key === val)


Desnoods doe je het in 2 of 3 regels als je deze one-liner niet leesbaar vindt. Bijkomend voordeel van deze aanpak is dat je alle matchende items terugkrijgt (en je dus niet zomaar de laatste pakt).

Ik hoop dat je linter deze code wel goedkeurt. Zo niet, dan lijkt hij me iets te strikt (hoe kun je immers anders nog een beetje fatsoenlijk functioneel programmeren?).

Voor een echt goed antwoord zou je moeten uitleggen wat je precies wilt, waarom je 'myArray' zo gestructureerd is (als een array met daarin objecten met daarin weer arrays, waaruit je weer items wilt plukken op basis van een key), wat je met het resulterende 'item' gaat doen, enzovoorts.

Alle reacties


Acties:
  • 0 Henk 'm!

  • Juup
  • Registratie: Februari 2000
  • Niet online
Guillome schreef op maandag 2 april 2018 @ 13:15:
JavaScript:
1
2
3
4
5
let val = 10;

myArray.forEach( row => {
    let item = row.data.find( rowItem => rowItem.key === val);
});


Dit werkt, maar het is niet netjes om een functie in een loop aan te maken.
Je maakt hier geen function in een loop.
Die functie wordt maar 1x aangemaakt.

Een wappie is iemand die gevallen is voor de (jarenlange) Russische desinformatiecampagnes.
Wantrouwen en confirmation bias doen de rest.


Acties:
  • 0 Henk 'm!

  • frankmulder
  • Registratie: Januari 2010
  • Laatst online: 06-10 21:13
Ik zie niet in waarom je de functie buiten de forEach zou verhuizen; het maakt je code alleen maar minder leesbaar. Het enige wat ik "niet netjes" vind is dat je een 'forEach' en een 'let' gebruikt terwijl je gewoon een waarde aan het zoeken bent in een datastructuur. Daar zou ik een 'immutable' oplossing voor gebruiken, met functies zoals 'filter'. (En dan ook even nadenken of je echt wel het laatste item wilt terugkrijgen dat je vindt, zoals je nu doet.)

Acties:
  • 0 Henk 'm!

  • Guillome
  • Registratie: Januari 2001
  • Niet online
Omdat mijn JS linter aangeeft:
"Don`t make functions within a loop".

Elke keer dat hij door de loop gaat maakt ie die functie nu aan. Als je de functie naar buiten verplaatst niet, dan voert hij die enkel uit.

If then else matters! - I5 12600KF, Asus Tuf GT501, Asus Tuf OC 3080, Asus Tuf Gaming H670 Pro, 48GB, Corsair RM850X PSU, SN850 1TB, Arctic Liquid Freezer 280, ASUS RT-AX1800U router


Acties:
  • 0 Henk 'm!

  • Juup
  • Registratie: Februari 2000
  • Niet online
Maar dat komt door je binnenste functie.
JavaScript:
1
rowItem => rowItem.key === val

Edit: oh ja dat zei je zelf ook al 8)7

[ Voor 18% gewijzigd door Juup op 02-04-2018 13:33 ]

Een wappie is iemand die gevallen is voor de (jarenlange) Russische desinformatiecampagnes.
Wantrouwen en confirmation bias doen de rest.


Acties:
  • 0 Henk 'm!

  • Gropah
  • Registratie: December 2007
  • Niet online

Gropah

Admin Softe Goederen

Oompa-Loompa 💩

Lees eens een keer de documentatie van arrow functions, op bijvoorbeeld Mozilla Developer Network. Wat je gebruikt zijn lambda functie's, maar die kun je ook prima buiten de forEach definieren en dan daarbinnen gebruiken. Daarmee los je je lint probleem waarschuwing op. Maar ik mag hopen dat dit redelijk snel automatisch weggeoptimaliseerd word door je interpreter.

Acties:
  • Beste antwoord
  • 0 Henk 'm!

  • frankmulder
  • Registratie: Januari 2010
  • Laatst online: 06-10 21:13
Als het je er echt om gaat dat je die waarschuwing wegwerkt, kun je eens kijken op StackOverflow (bijvoorbeeld https://stackoverflow.com...ons-within-a-loop#3038555).

Als je gewoon je code wilt verbeteren (en dat lijkt me een betere instelling), dan zou ik zoiets doen:
JavaScript:
1
const items = [].concat(...myArray.map(row => row.data)).filter(item => item.key === val)


Desnoods doe je het in 2 of 3 regels als je deze one-liner niet leesbaar vindt. Bijkomend voordeel van deze aanpak is dat je alle matchende items terugkrijgt (en je dus niet zomaar de laatste pakt).

Ik hoop dat je linter deze code wel goedkeurt. Zo niet, dan lijkt hij me iets te strikt (hoe kun je immers anders nog een beetje fatsoenlijk functioneel programmeren?).

Voor een echt goed antwoord zou je moeten uitleggen wat je precies wilt, waarom je 'myArray' zo gestructureerd is (als een array met daarin objecten met daarin weer arrays, waaruit je weer items wilt plukken op basis van een key), wat je met het resulterende 'item' gaat doen, enzovoorts.

Acties:
  • 0 Henk 'm!

  • Guillome
  • Registratie: Januari 2001
  • Niet online
Ik heb voor dit issue ondertussen er een dictionary (key: entity) van gemaakt, want het is een lijst met identities waar ik de juiste entity bij wil pakken. Dan is find natuurlijk overbodig, was stukje oudere code :)

Dus min of meer wat jij zegt frank. Jouw stack link verwijst naar een oplossing die ikzelf al als laatste noemde.

[ Voor 13% gewijzigd door Guillome op 02-04-2018 14:32 ]

If then else matters! - I5 12600KF, Asus Tuf GT501, Asus Tuf OC 3080, Asus Tuf Gaming H670 Pro, 48GB, Corsair RM850X PSU, SN850 1TB, Arctic Liquid Freezer 280, ASUS RT-AX1800U router


Acties:
  • 0 Henk 'm!

  • Ed Vertijsment
  • Registratie: Juli 2014
  • Laatst online: 05-10 09:29
Bedenk je eerst dat een linter de kwaliteit van code bewaart. Elke oplossing op je vraag die de kwaliteit van je code niet ten goed komt (in de vorm van leesbaarheid = subjectief) kun je negeren. Ik vind persoonlijk je initiële oplossing dan ook niet perse verkeerd, het hang alleen een beetje van de rest van de omliggende code en complexiteit af.

Waar je misschien eerder naar wilt kijken is waarom je een anoniem object wilt gebruiken. Je kunt ook gewoon classes aanmaken voor een Row en een Cell een binnen je Row een method maken die de juiste cell teruggeeft op basis van en id. Je kunt ook via een omweg een Array extenden om dit te doen:

pseudo:

code:
1
2
3
4
row.getCellsByKey(key)
    .forEach(cell => {
        ...
    })


Een vergelijkbaar trucje heb ik hier gedaan: https://github.com/maykin...tion/src/abstract-list.js. Hier wordt Array geextend zodat er een nieuwe iterable ontstaat die naadloos met array werkt maar zelf wat basis intelligentie toevoegt.

[ Voor 3% gewijzigd door Ed Vertijsment op 02-04-2018 16:51 ]


Acties:
  • 0 Henk 'm!

  • q-enf0rcer.1
  • Registratie: Maart 2009
  • Laatst online: 11:27
frankmulder schreef op maandag 2 april 2018 @ 14:13:
Als het je er echt om gaat dat je die waarschuwing wegwerkt, kun je eens kijken op StackOverflow (bijvoorbeeld https://stackoverflow.com...ons-within-a-loop#3038555).

Als je gewoon je code wilt verbeteren (en dat lijkt me een betere instelling), dan zou ik zoiets doen:
JavaScript:
1
const items = [].concat(...myArray.map(row => row.data)).filter(item => item.key === val)


Desnoods doe je het in 2 of 3 regels als je deze one-liner niet leesbaar vindt. Bijkomend voordeel van deze aanpak is dat je alle matchende items terugkrijgt (en je dus niet zomaar de laatste pakt).

Ik hoop dat je linter deze code wel goedkeurt. Zo niet, dan lijkt hij me iets te strikt (hoe kun je immers anders nog een beetje fatsoenlijk functioneel programmeren?).

Voor een echt goed antwoord zou je moeten uitleggen wat je precies wilt, waarom je 'myArray' zo gestructureerd is (als een array met daarin objecten met daarin weer arrays, waaruit je weer items wilt plukken op basis van een key), wat je met het resulterende 'item' gaat doen, enzovoorts.
Dat is een mooie one-liner, maar houdt er wel rekening mee dat als je met een modern JavaScript framework werkt dat gebruik maakt van de object reference, je hiermee wel je change detector op hol laat slaan omdat je feitelijk een nieuwe array aanmaakt.

Acties:
  • 0 Henk 'm!

  • frankmulder
  • Registratie: Januari 2010
  • Laatst online: 06-10 21:13
q-enf0rcer.1 schreef op maandag 2 april 2018 @ 22:35:
[...]


Dat is een mooie one-liner, maar houdt er wel rekening mee dat als je met een modern JavaScript framework werkt dat gebruik maakt van de object reference, je hiermee wel je change detector op hol laat slaan omdat je feitelijk een nieuwe array aanmaakt.
Het ligt er maar net aan binnen welke context je dit gebruikt. Als je het bijvoorbeeld in een Redux-context gebruikt móet je wel een nieuwe array teruggeven. En het is maar de vraag of zo'n variabele in een "change detector" terechtkomt. Maar goed, als algemene waarschuwing kan het wel nuttig zijn wat je zegt.

Dat gezegd hebbende: de TS heeft de boodschap begrepen en heeft de datastructuur zodanig aangepast dat dit soort one-liners helemaal niet nodig zijn. :)

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
q-enf0rcer.1 schreef op maandag 2 april 2018 @ 22:35:
[...]


Dat is een mooie one-liner, maar houdt er wel rekening mee dat als je met een modern JavaScript framework werkt dat gebruik maakt van de object reference, je hiermee wel je change detector op hol laat slaan omdat je feitelijk een nieuwe array aanmaakt.
Houd er ook rekening mee dat "let" geen standaard is en 1 op de 10 gebruikers geen ondersteuning heeft voor ES6 ... https://caniuse.com/#search=ES6 (waarbij frameworks sowieso debiel zijn, omdat je die niet kan opdringen aan de client).

Acties:
  • +1 Henk 'm!

  • 418O2
  • Registratie: November 2001
  • Laatst online: 16:28
b2vjfvj75gjx7 schreef op dinsdag 3 april 2018 @ 01:23:
[...]


Houd er ook rekening mee dat "let" geen standaard is en 1 op de 10 gebruikers geen ondersteuning heeft voor ES6 ... https://caniuse.com/#search=ES6 (waarbij frameworks sowieso debiel zijn, omdat je die niet kan opdringen aan de client).
Gelukkig is er Babel

Acties:
  • +1 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Tja, het niet kunnen gebruiken van een zinloos framework, oplossen met een 3rd party deprecated library is ook een optie ... als je de originele vraagstelling in 2 plain-vanilla .JS regels kan schrijven :p

Acties:
  • 0 Henk 'm!

  • 418O2
  • Registratie: November 2001
  • Laatst online: 16:28
b2vjfvj75gjx7 schreef op dinsdag 3 april 2018 @ 01:28:
[...]


Tja, het niet kunnen gebruiken van een zinloos framework, oplossen met een 3rd party deprecated library is ook een optie ... als je de originele vraagstelling in 2 plain-vanilla .JS regels kan schrijven :p
Sja, wat is vanilla js? Maar ik gok dat vrij veel code toch al transpiled wordt

Acties:
  • +1 Henk 'm!

  • Ed Vertijsment
  • Registratie: Juli 2014
  • Laatst online: 05-10 09:29
b2vjfvj75gjx7 schreef op dinsdag 3 april 2018 @ 01:28:
[...]


Tja, het niet kunnen gebruiken van een zinloos framework, oplossen met een 3rd party deprecated library is ook een optie ... als je de originele vraagstelling in 2 plain-vanilla .JS regels kan schrijven :p
Ik snap niet zo goed naar welk "zinloos framework" hier gerefereerd wordt. Elk framework/library heeft zijn eigen use cases en de context bepaald of het zinloos of waardevol is.

Als je naar Babel refereert als "3rd party deprecated library" kloppen alleen de eerste 2 woorden. "3rd party" deprecated en library zijn niet aan de orde (wel voor bijvoorbeeld babel-polyfill maar d'as wat anders).

Babel is een compiler die taal X naar JavaScript omzet. Dat kan ES6, TypeScript of JSX zijn, dat maakt niet uit. Als naar JS compilen bad practice is kunnen we ook TypeScript droppen.

Begrijp mij niet verkeerd er is niets mis met "old-skool" ES5 typen. Dat kan er ook mooi uitzien en hoeft echt niet altijd lelijk maar het is echt niet de enige manier om dingen te doen.

Acties:
  • +1 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Ed Vertijsment schreef op dinsdag 3 april 2018 @ 10:18:
[...]

Begrijp mij niet verkeerd er is niets mis met "old-skool" ES5 typen. Dat kan er ook mooi uitzien en hoeft echt niet altijd lelijk maar het is echt niet de enige manier om dingen te doen.
Helemaal mee eens :)

Het ging mij er meer om dat er wel heel vaak naar frameworks / boilerplates wordt gegrepen om iets op te lossen, terwijl het ook in native JS kan.

Al die angular / react / node / etc... zaken maken niet automagisch opeens zaken mogelijk die in vanilla-JS niet kunnen; alleen de syntax / architectuur is anders.

Vaak genoeg meegemaakt dat er zo'n 20 jarige script-kiddie eist dat iets in angular of react wordt geschreven, terwijl vanilla-JS het in 5 regels doet...

Acties:
  • 0 Henk 'm!

  • 418O2
  • Registratie: November 2001
  • Laatst online: 16:28
b2vjfvj75gjx7 schreef op dinsdag 3 april 2018 @ 23:07:
[...]


Helemaal mee eens :)

Het ging mij er meer om dat er wel heel vaak naar frameworks / boilerplates wordt gegrepen om iets op te lossen, terwijl het ook in native JS kan.

Al die angular / react / node / etc... zaken maken niet automagisch opeens zaken mogelijk die in vanilla-JS niet kunnen; alleen de syntax / architectuur is anders.

Vaak genoeg meegemaakt dat er zo'n 20 jarige script-kiddie eist dat iets in angular of react wordt geschreven, terwijl vanilla-JS het in 5 regels doet...
Ik snap je opmerking over Babel alleen nog steeds niet. Ik volg je compleet over misbruik van frameworks, maar Babel gebruiken zodat je let kan gebruiken in je JavaScript is toch niet gek?

Acties:
  • 0 Henk 'm!

  • Foxl
  • Registratie: Juli 2002
  • Niet online
b2vjfvj75gjx7 schreef op dinsdag 3 april 2018 @ 23:07:
[...]


Helemaal mee eens :)

Het ging mij er meer om dat er wel heel vaak naar frameworks / boilerplates wordt gegrepen om iets op te lossen, terwijl het ook in native JS kan.

Al die angular / react / node / etc... zaken maken niet automagisch opeens zaken mogelijk die in vanilla-JS niet kunnen; alleen de syntax / architectuur is anders.

Vaak genoeg meegemaakt dat er zo'n 20 jarige script-kiddie eist dat iets in angular of react wordt geschreven, terwijl vanilla-JS het in 5 regels doet...
Het gaat er vooral om dat je het wiel niet tig keer opnieuw uit hoeft te vinden. Natuurlijk, als je niet weet hoe JS werkt ga je sowieso tegen een muur aanlopen, maar eventjes een library a-la ReactJS opnieuw uitvinden (én onderhouden) is gewoon water naar de zee dragen. Het kán homebrew met vanilla JS, maar dat moet je gewoon niet willen, dat wordt onhandelbaar.

Maar dat ligt natuurlijk ook aan de orde van grootte; een kek effectje of sort fix je in pure JS, een PWA met state storage en de hele shebang, dan ga je al snel echt een solide framework willen hebben.

/off-topic

I'm really easy to get along with, once you people learn to worship me...


Acties:
  • 0 Henk 'm!

  • n8n
  • Registratie: Juni 2007
  • Laatst online: 11:50

n8n

Met je tweede en vierde oplossing ben je er bijna.

code:
1
2
3
4
5
6
7
let val = 10;
const delegateFindItem = val => rowItem => rowItem.key === val;
const delegateFindItemVal = delegateFindItem(val);

myArray.forEach(row => {
    let item = row.data.find(delegateFindItemVal);
});


De tweede oplossing zou je als geheel ook in een eigen functie kunnen stoppen met `val` en `myArray` als parameters.

code:
1
2
3
4
5
6
7
const doStuff = (key, array) => {
  const equalByKey = item => item.key === key
  array.forEach(row => {
    const item = row.data.find(equalByKey)
    // ...
  })
}


ik zou zelf in dit geval eerder naar reduce/map/filter kijken ipv forEach.

[ Voor 59% gewijzigd door n8n op 06-04-2018 13:18 ]


Acties:
  • 0 Henk 'm!

  • BarôZZa
  • Registratie: Januari 2003
  • Laatst online: 13:35
@Guillome Bind is precies daarvoor bedoeld.
Foxl schreef op dinsdag 3 april 2018 @ 23:58:
[...]

Het gaat er vooral om dat je het wiel niet tig keer opnieuw uit hoeft te vinden. Natuurlijk, als je niet weet hoe JS werkt ga je sowieso tegen een muur aanlopen, maar eventjes een library a-la ReactJS opnieuw uitvinden (én onderhouden) is gewoon water naar de zee dragen. Het kán homebrew met vanilla JS, maar dat moet je gewoon niet willen, dat wordt onhandelbaar.

Maar dat ligt natuurlijk ook aan de orde van grootte; een kek effectje of sort fix je in pure JS, een PWA met state storage en de hele shebang, dan ga je al snel echt een solide framework willen hebben.

/off-topic
offtopic:
De onderhoudbaarheid van de code is niet afhankelijk van of iets vanilla is of met een framework is geschreven. Ik heb prima gestructureerde vanilla JS gezien, maar ook de meest smerige React code. Sterker nog, ik vind React al snel smerig met al die JSX, waarbij alles op één grote hoop gegooid wordt zonder seperation of concerns (html in je javascript met click handlers met daarin weer javascript en vaak zelfs old school style tags 8)7 ). Het nodigt uit om iets snel in elkaar te hacken, een beetje zoals in het pre-css tijdperk. Lijkt me vreselijk als het uit de mode raakt en je over een tijdje met een oude codebase zit of tig versies achterloopt en wil upgraden.

Niet dat het niet netjes kan, maar de meeste code die ik op het web voorbij zie komen is dramatisch. Het lijkt wel alsof de JQuery-scripters nu massaal aan de React zitten.

En ja ik schrijf (P)WA's in vanilla js incl state storage, routers, webworkers, renderers, animaties, in memory db, indexeddb etc. De js is minified rond de 10kb in totaal. Stuk makkelijker om soepel te laten lopen op mobiel en om bijvoorbeeld de rendering te optimaliseren zodat je vrijwel altijd de 60fps raakt.

Acties:
  • 0 Henk 'm!

  • Ed Vertijsment
  • Registratie: Juli 2014
  • Laatst online: 05-10 09:29
BarôZZa schreef op vrijdag 6 april 2018 @ 14:28:

offtopic:
[..] ik vind React al snel smerig met al die JSX, waarbij alles op één grote hoop gegooid wordt zonder seperation of concerns (html in je javascript met click handlers met daarin weer javascript en vaak zelfs old school style tags 8)7 [...]
Dat van die style tags ben ik met je eens (naast ook andere dingen), het eerste punt "separation of concerns" zie ik echter anders.

Een veel gemaakte fout is dat React geïmplementeerd wordt als MVC, dat is niet het idee achter React. Het idee erachter is dat je "self contained" schrijft. Je maakt 1 ding en alles voor dat ene ding zit erin. Vanuit deze gedachte komt ook het idee om inline styles terug te brengen.

Die inline styles walg ik van omdat je, je component netto bijna nooit kan hergebruiken (en andere technische redenen) maar een render stap met een klein beetje JSX erin vind ik niet zo'n heel groot probleem als ik daarmee de hele flow van het component op 1 scherm kan hebben staan (even aangenomen dat er dan niet nog grote concepten als Redux/MobX bij komen kijken).
Pagina: 1