ugrás a tartalomhoz

Melyik kódot használjátok?

inf · 2014. Szep. 22. (H), 00.49
Melyik megközelítést használjátok a kettő közül, és miért?

1.)
var a = [0,1,2];
for (var i=0, l=a.length; i<l; ++i) {
	var v = a[i];
	//...
}
2.)

var a = [0,1,2];
for (var i=0, l=a.length; i!=l; ++i) {
	var v = a[i];
	//...
}
(A forEach-et most felejtsük el egy pillanatra.)
 
1

Lehetőség szerint az

H.Z. · 2014. Szep. 22. (H), 01.08
Lehetőség szerint az elsőt.
Itt ugyan nincs jelentősége, de jobb megszokni, hogy ilyen esetben ne egyenlőségre vizsgálj, mert vannak helyzetek, amikor az ==, ===, != végtelen ciklusba viszik a programot.

Ilyesmire gondoltál?
2

Persze, de kíváncsi vagyok a

inf · 2014. Szep. 22. (H), 01.37
Persze, de kíváncsi vagyok a többiek válaszára is. :-)
7

De ugye majd elmondod, hogy

H.Z. · 2014. Szep. 22. (H), 09.29
De ugye majd elmondod, hogy miért érdekel? ;)
15

A végtelen ciklushoz való

inf · 2014. Szep. 23. (K), 05.07
A végtelen ciklushoz való hozzáállás miatt kérdeztem. Elméletileg a "!=" gyorsabb, mint a "<", az végeredmény pedig ugyanaz, szóval semmi értelme kacsacsőrözni.

Nekem ha nem kacsacsőrt teszek, akkor az a 15 éves beidegződés fut át az agyamon, hogyha valamiért átugorja a length értéket az index - mondjuk a kozmikus sugárzás miatt - akkor végtelen ciklusba kerül a program. Sok éve js-ben ilyenkor lefagyott a böngésző, és elég kényelmetlen volt újraindítgatni és debuggolni, hogy vajon hol van a végtelen ciklus.

Manapság már nincs ilyen probléma több ok miatt sem:
- Végtelen ciklusnál megkérdi a böngésző, hogy leállítsa e a programot.
- TDD-vel fejlesztve pontosan lehet tudni, hogy hol a hiba a kódban.
- Általában az ember nem törődik előre az optimalizálással, és forEach-et használ.
18

Ha integereket vizsgálsz,

MadBence · 2014. Szep. 23. (K), 13.29
Ha integereket vizsgálsz, akkor a kacsacsőr pont olyan gyors, mint az egyenlőségvizsgálat. Ha lebegőpontos, akkor meg az egyenlőségvizsgálat értelmetlen (lásd: 0.1 + 0.2 == 0.3 // false).
20

Okés, kösz az infot.

inf · 2014. Szep. 23. (K), 16.35
Okés, kösz az infot.
3

Első

Hidvégi Gábor · 2014. Szep. 22. (H), 08.24
Érzésre az egyenlőség vizsgálata gyorsabban elvégezhető, de a második csak akkor használható, ha biztosan tudod, hogy a ciklus változóját mindig eggyel növeled.
4

kisebb

szabo.b.gabor · 2014. Szep. 22. (H), 08.43
Ha csibecsőr vs egyenlőség jel a kérdés, akkor én is csibecsőrre szavazok, egyrészt a 'végtelen ciklus miatt', meg mert szerintem jobban olvasható (bár lehet, hogy csak megszokás).

A másik gyorsabb lenne amúgy? Vagy miért jó? Ha ez szól mellette én akkor sem használnám ezt a micro optimalizációt.

Mindazonáltal egy

echo $x.'bigyo'.$y;
vs.
echo $x,'bigyo',$y;

optimalizálást simán meglépek, mert nem ront az olvashatóságon.
6

Assembly/gépi szinten

H.Z. · 2014. Szep. 22. (H), 09.28
Assembly/gépi szinten gyorsabb az egyenlőség vizsgálata.
Amikor utoljára assembly-ben programoztam, akkor egy xor művelet, utána meg ha jól emlékszem, egy jz/jnz utasítás, ami összeségében két órajel ciklust igényelt, míg a hasonlítás hármat vagy többet.

Ciklusokra meg volt olyan, hogy decrement (lehetőleg regisztert) és utána a jz/jnz (ugrás ha nulla/nem nulla az eredmény)
32

Nem egészen

vbence · 2014. Szep. 24. (Sze), 10.54
Alapvetően nincs különbség. A cmp (compare) sok flaget befolyásol: egyenlőség esetén a Z, túlcsordulás - kisebb - esetén a C.

Egyenlőségvizsgálat
ciklus:

; ciklusmag

mov ax, [ i]
cmp ax, [ l]
jne ciklus ; jump if not equal (alias jnz)
Reláció vizsgálat
ciklus:

; ciklusmag

mov ax, [ i]
cmp ax, [ l]
jb ciklus ; jump if below (alias jc)
Lehet mikrooptimalizálni a xor-ral, akkor viszont ne felejtsük el, hogy a regiszter (a példában ax) értéke megsemmisül, és tölthetjük be újra a memóriából a (cilus)változónkat, míg a fenti cmp-s példában a ciklusváltozó tovább használható.

Amit ebből haza lehet vinni, hogy nincs számottevő különbség. Ez pont az a zóna, ahol a döntés hatása elvész a JIT fordító optimizálása okozta zajban.
33

Nem mostani processzorokról

H.Z. · 2014. Szep. 24. (Sze), 11.36
Nem mostani processzorokról beszéltem.
(ezeknek már nem ismerem az assembly-jét/gépikódját - amit emlegettem... azon még tudtam, hogy mi, hány órajelciklust igényel :) )

Egyébként is ciklusszervezésről volt szó, ami korábban úgy nézett ki assemly szinten, hogy (többnyire) regiszterbe töltve a lefutások darabszáma, azt egy decrement utasítással csökkentem és a decrement mögé csak egy olyan jump kellett, ami a decrement által beállított flag függvényében ugrott, ha az eredmény nulla lett.
Ennek a helyére betenni egy hasonlító műveletet, rengeteget tudott lassítani a kódon.
34

Ezek 8086-os utasítások, én

vbence · 2014. Szep. 24. (Sze), 13.30
Ezek 8086-os utasítások, én sem praktizálok aktívan assemblyt manapság. ;)

Igen, a klasszikus ciklusvezérlés asm-ben az, amikor a cx regiszer tartalmazza a futások számát, ezt a cikus végén egyel csökkentjük, majd ha ez eredmény nem nulla ugrunk a cikus elejére (dec cx, jnz cikus) - ezt a kettőt egyszerre elköveti a loop utasítás.

Erre csak akkor fordítható le biztonsággal egy JS ciklus, ha a cikusváltozóra nem hivatkozunk a ciklusmagban (vagyis nincs elvárás a programozó részéről az i által felvett értékekről).

Néhányan írnak pl ilyen (lefelé számláló) cikust az optimalzálás jegyében, ezt el tudom képzelni, hogy ez valódi natív asm loppá fordul:
for (var i=tomb.length; i>0; i--) {
    // cilusmag
}
... néha nem fontos, hogy milyen sorrendben dolgozzuk fel az elemeket.
36

Én viszont elakadtam valahol

H.Z. · 2014. Szep. 24. (Sze), 15.04
Én viszont elakadtam valahol a néhai mainframe utánzat R22, meg a Z80 környékén. ;)
Azóta nem foglalkoztam assembly-vel :(
5

Én mindig az elsőt használom,

tisch.david · 2014. Szep. 22. (H), 08.48
Én mindig az elsőt használom, a véletlen végtelen ciklus kiküszöbölése miatt. Ugyanilyen kódvédelmi szempontból teszem ki mindig a {}-eket az if/else után, és írok mindig default ágat a switch-be, akkor is, ha ez fölöslegesnek tűnik.
8

Egyiket sem

Poetro · 2014. Szep. 22. (H), 10.08
Szerintem a változó nevek nem megfelelőek, nem szeretem a prefix operátort, a var kulcsszó a cikluson belül félrevezető lehet.
Ha nem számít a sorrend, akkor a következőt szoktam használni:
for (var i = a.length, value; i--;) {
    value = a[i];
    //...
}
24

+1

bamegakapa · 2014. Szep. 23. (K), 17.41
Én is amellett vagyok, hogy a value értékadása a ciklustörzsben legyen (ha egyáltalán szükséges). Szerintem olvashatóbb így.
9

harmadikat (negyediket)

razielanarki · 2014. Szep. 22. (H), 17.18
(feltételezve h a tömb folytonos, javascript)
for (var i = 0, elem; elem = array[i]; i++)
{
   // do stuff with elem
}
10

folytonos?

Poetro · 2014. Szep. 22. (H), 17.37
És azt is feltételezed, hogy mindig igaz értékeket tárol, azaz egyik érték sem false, null, undefined, NaN, "", 0
14

feltételezem,

razielanarki · 2014. Szep. 22. (H), 23.03
gyakorlatban kevésszer jön elő h falsy érték van a tömbben, de ha mégis számítani lehet rá, akkor
(elem=array[i]) !== undefined
van a loop expressiönben.
17

Melyik a kakukktojás? :D elem

inf · 2014. Szep. 23. (K), 05.18
Melyik a kakukktojás? :D

elem = array[i] || array[i] !== undefined
elem = array[i] || elem !== undefined
(elem = array[i]) || elem !== undefined
19

utolsó

razielanarki · 2014. Szep. 23. (K), 16.17
az utolsó, mert a többinél mást guardol a || :)
21

A középső :-) Ha nem teszed

inf · 2014. Szep. 23. (K), 16.37
A középső :-) Ha nem teszed zárójelbe, akkor csak a feltétel vizsgálata után történik meg az értékadás, és mivel az elem-nél undefineddel kezdesz, ezért elhal a ciklusod már az elején.
22

ez igaz :)

razielanarki · 2014. Szep. 23. (K), 17.28
viszont az első két esetben nem mindig az kerül az elem-be amit szeretnénk (elvileg)
23

Igen, ha array[i] = 0, akkor

bamegakapa · 2014. Szep. 23. (K), 17.37
Igen, ha array[i] = 0, akkor az elem
elem = array[i] || array[i] !== undefined  //true
elem = array[i] || elem !== undefined      //false
(elem = array[i]) || elem !== undefined    //0
25

Igaz. Aki másnak vermet ás...

inf · 2014. Szep. 23. (K), 19.55
Igaz. Aki másnak vermet ás... :D
26

jah

razielanarki · 2014. Szep. 23. (K), 21.17
de ha a tömb nem tartalmaz falsy értéket, akkor az eredmény szempontjából tényleg a második a hibás :) (azóta végiggondoltam.. asszem :D )
28

Szerintem ha nem tartalmaz

bamegakapa · 2014. Szep. 23. (K), 22.00
Szerintem ha nem tartalmaz falsy értéket a tömb, akkor mindegyik helyesen fog működni. A || utáni rész nem fog kiértékelődni egyik esetben sem.

Szerk.: eh, ez nyilván hülyeség, a második olyan végtelen ciklust okoz, hogy öröm nézni, mivel az elem előző értéke nem lesz undefined, amikor pont kilépnénk a tömbből. Az állításom úgy helyes, ha nem ciklusban vizsgáljuk a dolgot, hanem array[i] = 1, ez esetben mindhárom sor 1-et ad vissza, és a || utáni rész nem értékelődik ki :).
30

Egyik sem okoz végtelen

inf · 2014. Szep. 24. (Sze), 02.17
Egyik sem okoz végtelen ciklust :D
31

A második pedig azt okoz.

bamegakapa · 2014. Szep. 24. (Sze), 08.53
A második pedig azt okoz. Egyrészt kipróbáltam :), másrészt az indoklást már részeiben elmondtuk, csak nem raktuk össze.

1. Az elem = array[i] || elem !== undefined esetén a vizsgálat időpontjában az elem mindig még az előző értéket tartja.

2. Az elem értéke az értékadás után vagy array[i] lesz (ha az array[i] truthy) vagy true (ha array[i] undefined) vagy false (ha array[i] falsy de nem undefined).

Tehát nem csak egy plusz kört fog menni, mivel az elem soha nem lesz === undefined. A ciklus csak akkor nem lesz végtelen, ha a tömb üres vagy az első értéke falsy, ez esetben még az első kör előtt leáll.

Jó volt a felvetésed, mert még másnapra is alig sikerült teljesen kibogoznunk :).
37

elem = array[i] || elem !==

inf · 2014. Szep. 24. (Sze), 18.22
elem = array[i] || elem !== undefined
Nézzük meg újra.

- truthy, ha array[i] truthy vagy az előző elem nem undefined volt.
- false, ha array[i] falsy és az előző elem undefined volt.

Na most az előző elem csak az elején lehet undefined. Utána mindenképp truthy lesz a végtelenségig. Nem egyszerű végiggondolni :D

Jó volt a felvetésed, mert még másnapra is alig sikerült teljesen kibogoznunk :).


Ja pedig ránézésre egy holt egyszerű kód... :-)
29

Nem, igazad van, tényleg csak

inf · 2014. Szep. 24. (Sze), 02.06
Nem, igazad van, tényleg csak a harmadik a jó. :D Asszem... :D

Az első falsy érték esetében true-t ad az érték helyett, mert array[i] || array[i] !== undefined ezt állítja be értéknek az array[i] helyett.

A másodikkal ennél egy fokkal érdekesebb. Az elem az array[i] || elem !== undefined értéket kapja, így ha array[0] alatt falsy értékkel találkozik, akkor el sem indul a ciklus, mivel az elem értéke a kiindulási állapotban undefined. A végén még valószínűleg hozzácsap plusz egy kört, mivel az elem !== undefined mindig az előző értéket nézi.

A harmadik (elem = array[i]) || elem !== undefined a zárójel miatt gyakorlatilag megegyezik azzal, hogy elem = array[i], elem || elem !== undefined, szóval az helyes.

Na látom mindenkit sikerült összezavarni a végére, még magamat is... :D
11

:-)

zzrek · 2014. Szep. 22. (H), 17.39
Ez tetszik, yópofa!
16

Jó látni, hogy mennyi

inf · 2014. Szep. 23. (K), 05.08
Jó látni, hogy mennyi változata van a legegyszerűbb kódnak is. :-)

Még ezen is lehet szépíteni azért:

for (var i = 0, elem; elem = array[i], elem !== undefined; ++i)
Bár mindenkinek szubjektív, hogy mi az olvashatóbb.
12

Kövezzetek meg

zzrek · 2014. Szep. 22. (H), 17.54
Kövezzetek meg, de én legtöbbször így használom:

var i,v,a=[1,2,3];
for (i=0; i<a.length; i++) 
{  
    //...  
}  
Vagyis ha nincs különösebb okom rá, nem segítek a fordítónak az optimalizálásban (optimalizálja ki ő, az a feladata). A legtöbbször rövid ciklusaim vannak, és a ciklusmag nagyságrenddel időrablóbb, mint a hosszvizsgálat. Természetesen ha muszáj, trükközök én is.
13

Kiegészítés

Hidvégi Gábor · 2014. Szep. 22. (H), 20.45
Az én szövegszerkesztőmben van automatikus kódkiegészítés, beírom, hogy for, nyomok egy szóközt, és magától beteszi a megfelelő kódrészletet, a kurzor a .length előtt villog, oda csak be kell gépelni a tönb nevét.
35

+1

Pepita · 2014. Szep. 24. (Sze), 14.02
nem segítek a fordítónak az optimalizálásban (optimalizálja ki ő, az a feladata)

És - szerintem - sokkal olvashatóbb is, és ha már forráskódról beszélünk, legyen is olvasható.
27

Első, kizárólag :)

BlaZe · 2014. Szep. 23. (K), 21.54
Első, kizárólag :) A jó kód mindig törekszik arra, hogy egyértelműen azt írja le amit csinál, ne legyen félrevezető. Az elsőnél ez teljesül, hiszen a ciklus azt csinálja, hogy növelgeti egy változó értékét amíg az kisebb, mint a kijelölt érték. A második ezzel szemben azt mondja, hogy növelgetjük egy változó értékét, és ha pontosan megegyezik egy általunk kijelölt értékkel, akkor nem csináljuk tovább. Az első kijelöli az értékkészlet egy részhalmazát amire végrehajtjuk a ciklusmagot, a második kijelöl egy elemet, amire nem. Az ilyen kódból szoktak lenni a brutális szívások :)