ugrás a tartalomhoz

A JavaScript, ami tömörödik

Joó Ádám · 2010. Júl. 28. (Sze), 21.26

A List Aparton megjelent Better JavaScript Minification című cikke folytatásában Nicholas C. Zakas újabb módszereket mutat be JavaScript kódunk tömöríthetőségének javítására.

Első írásában az eval() függvény és a with használatának kerülését hangsúlyozta.

A második részben a globális változók, az objektumtulajdonságok és a kulcsszavak érinthetetlenségéből fakadó tetemes elvesztegetett tömörítési potenciál megmentésére vonatkozóan ad hasznos tanácsokat.

A globális változók nem cserélhetők rövidebb nevekre, ugyanis a tömörítő nem tudhatja, azok mely más helyeken kerülnek esetleg felhasználásra. A cél tehát (mely egyébként is követendő szabály), hogy a lehető legkevesebbre csökkentsük a létrehozott globális változók számát, a készen kapottakat pedig azonnal tegyük lokálissá.

  1. function doSomething() {  
  2.     var doc = document;  
  3.   
  4.     // Itt a változó már lokális, tehát a neve rövidíthető  
  5. }  

Az esetek nagy többségében ha a programunk több részéből is elérhető változóra van szükségünk, akkor sincs igény arra, hogy ezt más programok is elérjék: nem globális, csak a legfelsőbb szintű hatókörben elhelyezett változó kell nekünk. Egy önhívó névtelen függvény tehát ideális a célra:

  1. (function () {  
  2.     var firstLongVariable, secondLongVariable;  
  3.   
  4.     function doSomething() {  
  5.         // Ő eléri a két változót  
  6.     }  
  7.   
  8.     function doOtherThing() {  
  9.         // És ő is  
  10.     }  
  11. })()  
  12.   
  13. // Itt viszont már nem érhetők el  

Az objektumtulajdonságok esetében hasonló a helyzet, mint a globális változóknál, azok nem rövidíthetők le. A megoldás is ugyanaz: az egynél többször használt kulcsot rendeljük egy helyi változóhoz, ami már biztonságosan átnevezhető a tömörítéskor. Mindig tartsuk észben, hogy ami pont után áll, az nem rövidíthető, így a célunk, hogy a pontok számát a lehető legkisebbre szorítsuk a kódunkban.

Ami a nyelv kulcsszavait illeti, ezek értelemszerűen nem cserélhetők le, így az egyetlen lehetőségünk, hogy eleve csökkentjük a számukat. A var esetén ezt megtehetjük az összevont deklaráció alkalmazásával.

  1. var firstLongVariable;  
  2. var secondLongVariable;  

helyett

  1. var firstLongVariable, secondLongVariable;  

A másik kulcsszó, melyen spórolhatunk, a return. Egyes iskolák egyébként is egyetlen visszatérési pontot ismernek csak el, mint üdvözítő gyakorlatot, tömörítési szempontból azonban vitán felül áll ezen tradíció követésének áldásos jellege.

  1. switch (someValue) {  
  2.     case 'foo':  
  3.         return 1;  
  4.         break;  
  5.     case 'bar':  
  6.         return 2;  
  7.         break;  
  8.     case 'foobar':  
  9.         return 3;  
  10.         break;  
  11.     default:  
  12.         return 0;  
  13. }  

sokkal hosszabb kimenetet eredményez, mint

  1. var result = 0;  
  2.   
  3. switch (someValue) {  
  4.     case 'foo':  
  5.         result = 1;  
  6.         break;  
  7.     case 'bar':  
  8.         result = 2;  
  9.         break;  
  10.     case 'foobar':  
  11.         result = 3;  
  12.         break;  
  13. }  
  14.   
  15. return result;  
A fenti technikák elsajátítása és alkalmazása akkor is jobb programozóvá tesz bennünket, ha nem kívánjuk tömöríteni a kódunkat; ha viszont igen, úgy egy kis odafigyeléssel sávszélességet és tárkapacitást spórolhatunk meg, elhanyagolható ráfordítással. 
1

switches példa

thgab · 2010. Júl. 29. (Cs), 06.13
A 2. switch-es példa hibás. A
  1. var result = 0;  
a switch elé kell, hogy kerüljön.
Másrészt, nem értem miért tömöríthető jobban a második switch példa,
hiszen az elsőből a break;-ek, a return miatt elhagyhatóak.
2

Másrészt, nem értem miért

Ajnasz · 2010. Júl. 29. (Cs), 09.24
Másrészt, nem értem miért tömöríthető jobban a második switch példa,

mert a return kulcsszo, igy nem cserelheto le 1 karakteres valtozonevre.
Ez a modszer nem csak switcheknel alkalmazhato, hanem barmely olyan fuggvenyben, ahol van visszateresi ertek. A fuggveny elejen definialsz egy valtozot amit a legvegen returnolsz, a fuggveny belsejeben pedig ennek adod a visszaadni kivant erteket.
3

a break sem, amit viszont a

Tyrael · 2010. Júl. 29. (Cs), 10.06
a break sem, amit viszont a minden agban return-os megoldasnal nem kellene kiirni.
legalabbis ezt probalja megertetni a kerdezo, ugy tunik sikertelenul.

a='valtozoHosszusaguErtek';break;
az imho hoszabb, mint a
return 'valtozoHosszusaguErtek';

legalabbis ha az ertek hoszabb mint 2-3 karakter.

es ugye a masodik esetben meg kellene egy
var a;
az elejere, meg egy
return a;
a vegere.

szoval ertem a lenyeget, csak rossz a pelda.

Tyrael
4

Igen, a pelda a rossz, ezert

Ajnasz · 2010. Júl. 29. (Cs), 13.35
Igen, a pelda a rossz, ezert probaltam altalanosan kifejeteni. Egy if/else jobb pelda lehetne:
  1. if(a==b) {  
  2.   return 'asdf';  
  3. else {  
  4.   return 'foobar';  
  5. }  
vs
  1. var o='foobar';  
  2. if(a==b) {  
  3.   o='asdf';  
  4. }  
  5. return o;  
Plusz szerintem szebb is :]
6

Switch tipikusan az, amit nem

inf · 2010. Júl. 29. (Cs), 22.14
Switch tipikusan az, amit nem használ az ember, akkor már inkább külön metódusokba teszem a switch ágait, meg if-else-zek, vagy shortif-elek, ha már tömörítésről van szó.
  1. return someValue=='foo'?1:someValue=='bar'?2:someValue=='foobar'?3:0;  
Vagy map-be is szét lehet szedni a változatokat, ez az amivel a switchet legtöbbször kiváltom...
  1. return (  
  2. {  
  3.     foo: 1,  
  4.     bar: 2,  
  5.     foobar: 3  
  6. })[someValue] || 0;  
7

Gyakorlat

saxus · 2010. Júl. 29. (Cs), 22.58
Azért nekem picit több kódot tartalmazó switch-case-jaim szoktak lenni, mint egy szimpla értékválasztás, ott nem lehet megúszni ilyen egyszerűen.
9

De igen.

inf · 2010. Júl. 29. (Cs), 23.03
De igen.
10

return

Tyrael · 2010. Júl. 29. (Cs), 23.14
  1. return someValue=='foo'?1:someValue=='bar'?2:someValue=='foobar'?3:0;   
ezert en eltornem a kezed, ha egy csapatban dolgoznank. :)
zarojelek nelkul (ami a forditonak felesleges, a fejlesztonek nem) hihetetlenul olvashatatlan, es nagyon konnyu benezni.

Vagy map-be is szét lehet szedni a változatokat, ez az amivel a switchet legtöbbször kiváltom...

persze, ahol hashmappel kivalthato, ott konnyu.
de mondjuk egy szokoev-szamito fuggvenyben, amiben az evszambol megmondod, hogy szokoev-e, ott mar nem tudsz hashmap-et csinalni a switch kimeneteleibol.

Tyrael
13

Js engedi, hogy zárójelek

inf · 2010. Júl. 30. (P), 12.04
Js engedi, hogy zárójelek nélkül menjen, pl php nem engedné, meg szerintem más nyelv sem. Szerintem nem könnyű benézni, ha valaki ért js-hez.
Teljesen analóg ezzel:
  1. var r;  
  2. if (someValue=="foo"){r=1;}  
  3. else if (someValue=="bar"){r=2;}  
  4. else if (someValue=="foobar"){r=3;}  
  5. else {r=0;}  
  6. return r;  
Amúgy meg mappel hosszabb kódrészek:
  1. return (  
  2.     ({  
  3.         foo: function (){return 1;},  
  4.         bar: function (){return 2;},    
  5.         foobar: function (){return 3;}    
  6.     })[someValue] || function (){return 0;}  
  7. )();  
Más nyelvre is át lehet tenni, csak a feldolgozó metódusok nevei kellenek a map-be.

Ha kinyitsz bármilyen refaktorálásos könyvet, akkor kb első rész az, hogy a switch-ben lévő hosszabb részeket külön metódusokba kell tenni. Egyébként ha meg nem szeretnél több metódust, akkor sem jó a switch, mert elhagysz véletlenül egy break-et, aztán borul az egész, akkor már inkább if-else.
17

Szornyu

saxus · 2010. Júl. 31. (Szo), 01.19
Ne haragudjatok, de ezek egyre szornyubb megoldasok egy egesz egyszeru problemara...

Btw., aki egy if -nel az utasitasblokk kore nem rak zarojelet, annak mi kezet-labat torjuk.
18

Őszintén szólva annyira

inf · 2010. Júl. 31. (Szo), 05.13
Őszintén szólva annyira egyszerű a példa, hogy lusta voltam kitenni a zárójelet. De akkor közkívánatra:
  1. return (  
  2.     (someValue=='foo')              //Ha a someValue változó értéke foo,  
  3.     ?1                              //akkor 1  
  4.     :(  
  5.         (someValue=='bar')          //különben, ha az érték bar,  
  6.         ?2                          //akkor 2  
  7.         :(  
  8.             (someValue=='foobar')   //különben, ha az érték foobar,  
  9.             ?3                      //akkor 3,  
  10.             :0                      //az összes ellenkező esetben pedig 0  
  11.         )  
  12.     )  
  13. );                                  //a visszatérési érték.  
Hát ez van, más pornót néz, nektek meg ez okoz örömöt... :D


Megírtam a map-es változatot is, hátha valakinek nem volt érthető. Ezek után már nem lehet tudni.
  1. var MyClass=function (){};  
  2. MyClass.prototype.behaviourMap=  
  3. {  
  4.     foo: 'fooBehaviour',  
  5.     bar: 'barBehaviour',  
  6.     foobar: 'foobarBehaviour'  
  7. };  
  8. MyClass.prototype.getResult=function (someValue)  
  9. {  
  10.     var method=(someValue in this.behaviourMap)  
  11.         ?this.behaviourMap[someValue]  
  12.         :this.defaultBehaviour;  
  13.     return this[method].call(this);  
  14. };  
  15. MyClass.prototype.fooBehaviour=function ()  
  16. {  
  17.     return 1;  
  18. };  
  19. MyClass.prototype.barBehaviour=function ()  
  20. {  
  21.     return 2;  
  22. };  
  23. MyClass.prototype.foobarBehaviour=function ()  
  24. {  
  25.     return 3;  
  26. };  
  27. MyClass.prototype.defaultBehaviour=function ()  
  28. {  
  29.     return 0;  
  30. };  
  31.   
  32. var myInstance=new MyClass();  
  33. alert(myInstance.getResult("bar")); //2  
20

tisztaban vagyok vele, hogy

Tyrael · 2010. Júl. 31. (Szo), 18.10
tisztaban vagyok vele, hogy mire jo a map, arrol beszelek, hogy nem lehet, es nem is kell minden switch-et map-re cserelni.

Tyrael
21

Szerintem sem, szituáció

inf · 2010. Júl. 31. (Szo), 21.24
Szerintem sem, szituáció függő, van ahol ez a jó megoldás, van, ahol más.
12

Köszönöm!

thgab · 2010. Júl. 30. (P), 10.50
Igen erre próbáltam rávilágítani. Lehet, hogy túl tömör voltam. :)
5

Jogos

Joó Ádám · 2010. Júl. 29. (Cs), 17.06
Köszönöm, javítottam. És valóban, egy feltételvizsgálat talán megfelelőbb lett volna az elágazás helyett.
8

Haszon?

saxus · 2010. Júl. 29. (Cs), 23.02
Az ilyen kódtömörítőknek mennyi szokott a hatékonysága lenni úgy általában?

És mennyi a sima kód gzippelve és a tömörítő kompatibilissé tett kód gzippelve? Csak mert egy ideje azon a véleményen vagyok, hogy ilyenre akkor maximum akkor van lehetőség, ha egy adott projektre "végtelen sok" idő áll rendelkezésre, gyakorlatban nem mindig van igény erre, maximum nagyon-nagyon-nagy oldalak esetén és általában inkább megéri az olvasható, könnyen karbantartható kódot szem előtt tartani.
11

nezd meg pl. a jquery

Tyrael · 2010. Júl. 29. (Cs), 23.24
nezd meg pl. a jquery project-en.
160k vs 70k
http://code.jquery.com/jquery-1.4.2.js
http://code.jquery.com/jquery-1.4.2.min.js

jobb helyeken a js/css minify-olas, osszebuildeles, gzippelest,, css spriteositas, etc. a deploy soran automatikusan megtortenek, szoval a fejlesztoknek csak akkor para a debugolas, ha konkretan ezen eljarasok valamelyike bugos (volt ilyenre is pelda. :P).

en azon az allasponton vagyok, hogy ezt egyszer kell csak jol megcsinalni, aztan automatizalhato, es nagyon megeri, hiszen az oldal renderelesenek nagy resze nem a html oldal letoltese, hanem a dom felepitese, statikus fajlok letoltese, css/jss ertelmezese teszi ki.

Tyrael
15

Automatizálás vs. odafigyelés

Joó Ádám · 2010. Júl. 30. (P), 13.02
Van ugye az automatizálható része, amit egyszer kell megcsinálni, de a fentiek épp arról szólnak, hogy milyen kódolási gyakorlattal lehet igazán hasznossá tenni az eszközt.
19

ezzel tisztaban vagyok, sehol

Tyrael · 2010. Júl. 31. (Szo), 18.08
ezzel tisztaban vagyok, sehol nem is vitattam, a minify-olas ertelmerol beszeltem (marmint hogy szerintem nagyon is van letjogosultsaga)
szoval nem igazan ertem, hogy itt most ezt miert irod le nekem.

Tyrael
22

Kiegészítés

Joó Ádám · 2010. Júl. 31. (Szo), 23.34
Csak az „egyszer kell megcsinálni”-hoz akartam hozzátenni.
24

ok, ezzel egyetertek. Tyrael

Tyrael · 2010. Aug. 3. (K), 22.42
ok, ezzel egyetertek.

Tyrael
14

Nézd meg a cikket

Joó Ádám · 2010. Júl. 30. (P), 13.01
Nézd meg a hivatkozott cikket, ott szép számértékek vannak.
16

Comment-ezés

Adam · 2010. Júl. 30. (P), 14.31
Ugyebár ha azt vesszük, a fenti módosításokon felül a kódtömörítők kiveszik az összes comment-et is a kódból, így nagyon hatékony tud lenni… feltéve, ha az ember normálisan comment-ezi a kódját. Ugye comment-eztek?
23

Closure Compiler

Ajnasz · 2010. Aug. 3. (K), 15.06
Erdemes ranezni a google closure compilerre is, ami YUI Compressorhoz kepest kb 5%-al jobb tomoritest eredmenyezhet es kodoptimalizaciot is vegez!
Viszont ezzel mar ovatosan kell banni ha ADVANCED_OPTIMIZATIONS opciot hasznaljuk, mert komoly valtoztatasokat vegez a kodon.