Co byste měli vědět o JavaScriptu

Co byste měli vědět o JavaScriptu [5]: with je zlý čaroděj

Vítejte u dalšího dílu série článku “Co byste měli vědět o JavaScriptu”. K pátemu dílu jsem seriálu “nadělil vlastní štítek”:http://zapisnik.pepiino.cz/tagy/co-byste-meli-vedet-o-javascriptu/ a také “vlastní RSS”:http://zapisnik.pepiino.cz/tagy/co-byste-meli-vedet-o-javascriptu/feed/.

Dnes si povíme o konstrukci `with` a rovnou prozradím, že učiníte lépe, nebudete-li ji používat.

Konstrukce with
******************
Konstrukce `with` je určena ke zkrácení zápisu přístupu k vlastnostem objektů.
/—html

var osoba = {
    jmeno: "franta",
    prijmeni: "frantiskovec",
    velikostBot: 42
};

//v rámci bloku with mohu pracovat s vlastnostmi
//objektu 'osoba' podobně jako s lokálními proměnnými
with (osoba) {
   //vypíše "franta"
   console.log(jmeno); 
   //vypíše "frantiskovec"
   console.log(prijmeni); 
   //vypíše odpověď na základní otázku života, vesmíru a vůbec
   console.log(velikostBot); 
}

\—
“Zkuste si”:http://jsfiddle.net/pepiino/7g6QV/. Vypadá to užitečně, že? Ale třpyt neimplikuje zlato, jak již zajisté víme.

With nepřehledný a zrádný
******************

Představte si, že při čtení JavaScriptového kódu narazíte na následující pasáž:
/—html

with (neco) {
    olala = bubu;
}

\—
Poznáte, co uvedený kód dělá? Stát se mohou 4 různé věci, v závislosti na tom, zda jsou `olala` a `bubu` vlastnostmi objektu `neco`.
/—html

//olala je vlastností neco, bubu nikoli
neco.olala = bubu;
//bubu je vlastností neco, olala nikoli
olala = neco.bubu;
//bubu i olala jsou vlastnostmi neco
neco.olala = neco.bubu;
//bubu i olala nejsou vlastnostmi neco
olala = bubu;

\—

Vzhledem k dynamické povaze JavaScriptu nemůžete nijak snadno zaručit, že objekt bude mít vámi předpokládané vlastnosti. A pokud je nemá, může “zapsaná hodnota snadno skončit v globálním oboru platnosti”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-1-promenna-a-globalni-obor-platnosti/, což lehce způsobí obtížně odladitelné chyby. Také pokud čtete cízí (nebo vlastní, ale starý) kód a předpoklad existence vlastností není vyjádřen jinak (třeba v komentáři), budete mít nejspíš problém pochopit autorův záměr.

Žijte bez with
**************
`With` do JavaScriptu bezpochyby nepatří, proto byl ve striktním módu ECMAScriptu 5 vyřazen. “Ačkoliv lze dlouze diskutovat o zajímavých použitích této konstrukce”:http://stackoverflow.com/questions/61552/are-there-legitimate-uses-for-javascripts-with-statement, usnadníte si život, pokud se bez něj obejdete i vy.

Co byste měli vědět o JavaScriptu [4]: deklarace funkce a funkce jako výraz

Vítejte u dalšího dílu mého “seriálu o méně známých zákoutích JavaScriptu”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-0-uvod/. Pravidelný čtenář si zajisté všiml, že první tři díly měly něco společného. Všechny se nějak dotýkaly platnosti proměnných v JavaScriptu. Dnešní článek nebude výjimkou a bude trochu delší i náročnější, takže doporučuji lehce si osvěžit paměť prolétnutím předcházejících témat.

V prvním díle jsem psal o “deklaraci lokálních proměnných, klíčovém slovu `var` a globálním ‘scope'”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-1-promenna-a-globalni-obor-platnosti/, navázal jsem krátkou zmínkou o tom, “že v JavaScriptu jsou lokální proměnné platné vždy v rámci celé funkce”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-2-javascript-nema-block-level-scope/ a nakonec jsem se minulý týden rozepsal o méně známé vlastnosti: “variable hoisting”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-3-variable-hoisting/.

Continue reading

Co byste měli vědět o JavaScriptu [3]: variable hoisting

“Minule jsem krátce popsal”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-2-javascript-nema-block-level-scope, že v JavaScriptu jsou lokální proměnné platné vždy na úrovni celé funkce, nikoli v bloku. S tím silně souvisí vlastnost, která je v angličtině označována *variable hoisting*. Rozumný český překlad mě nenapadá (a žádný oficiální neznám), ale sousloví by se dalo kostrbatě přeložit jako “zdvihání proměnných”.

Zdvihám, zdviháš, zdviháme
******************
Princip je jednoduchý: interpret javascriptu při zpracování těla funkce nalezne všechny identifikátory “lokálních proměnných deklarovaných pomocí klíčového slova `var`”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-1-promenna-a-globalni-obor-platnosti/, a “vyzdvihne” je na začátek těla funkce (před jakýkoliv příkaz).

Takže následující kód:
/—html

function tulipan() {
    if (test()) {
        var promenna = 10;
        fanfan();
    }
    var hodnota = "malá";
    return "vysledek";
    var cislo = 1;
}

\—
Je interpretován jako:
/—html

function tulipan() {
    var promenna, hodnota, cislo;
    if (test()) {
        promenna = 10;
        fanfan();
    }
    hodnota = "malá";
    return "vysledek";
    cislo = 1;
}

\—

Proč je to důležité?
******************
Nuže podívejme se na několik ukázek kódu, kde neznalost tohoto principu způsobí vývojaří přinejmenším zmatení.

Přístup ke globální proměnné (či proměnné z nadřazených oborů platnosti):
/—html

var hodnota = 20; 
function delej() {
    console.log(hodnota);  
    var hodnota = 6;
    console.log(hodnota);
}
delej();

\—
“Můžete si vyzkoušet”:http://www.jsfiddle.net/pepiino/rPsbh/, že první volání `console.log` vypíše `undefined` a ne `20`, jak by mohl očekávat neznalec.

Podobně v následující ukázce bude hodnota proměnné `baf` uvnitr funcke `tulipan` vždy vyhodnocena jako “vychozi”.
/—html

var baf = 'fanfan';

function tulipan() {
  var baf = baf || 'vychozi'; 
  console.log(baf);
};

tulipan();

\—
“Vyzkoušejte si.”:http://www.jsfiddle.net/pepiino/QENXC/

Doporučení na závěr
******************
Běžným doporučením, na které můžete ohledně psaní kódu v JavaScriptu narazit, je právě používání jediného klíčového slova `var` hned na začátku funkce, kde uvedete všechny lokální proměnné. Pokud k JavaScriptu přijdete z jiného jazyka (jako třeba já z Javy), může to být zarážející. Důvodem je ale právě *variable hoisting*. Dodržování této rady vám může ušetřit pár nepříjemných záseků.

Příště navážu opět souvisejícím tématem, povíme si něco o deklaracích funkcí.

Co byste měli vědět o JavaScriptu [2]: JavaScript nemá “block-level scope”

V dnešním velice krátkém “dílu”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-0-uvod/ se zmínim o drobnosti, kterou by měli mít na paměti hlavně programátoři přicházející z jazyků jako je Java či C#. Vývojáře znalé třeba PHP ale zajisté nijak nezaskočí, ti zde budou jako doma. V JavaScriptu (podobně jako v PHP) je totiž *lokální proměnná platná vždy v rámci celé funkce*.

Oproti tomu ve zmiňované Javě je platnost omezena na blok kódu.
/—html

// Java
public void funkce() {
    int  i = 10;
    for (int i =0; i < 15; i++) {
        System.out.println("Uvnitr bloku i: " + i);
    }
    System.out.println("Vne bloku i: " + i);

}

\—
V uvedném kódu překryje proměnná `i` deklarovaná v záhlaví cyklu vnější proměnnou `i`.

V Javascriptu ale následující zápis postrádá smysl:

/—html

// JavaScript
function funkce() {
    var i = 10;

    for (var i = 0; i < 6; i++) {
        //neco...
    }

    for (var i = 0; i < 68; i++) {
        //neco jineho
    }

}

\—
Proměnná `i` bude prostě jenom jedna, bez ohledu na počet “použití klíčového slova `var`”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-1-promenna-a-globalni-obor-platnosti/.

S oborem platnosti na úrovni funkce silně souvisí další zajímavá vlastnost, nazývaná “variable hoisting”. Proberu ji příště.

Co byste měli vědět o Javascriptu [1]: proměnná a globální obor platnosti

V “prvním díle miniseriálu”:http://zapisnik.pepiino.cz/co-byste-meli-vedet-o-javascriptu-0-uvod/ zmíním jedno z nejznámějších špatných míst Javascriptu. V anglicky psaných zdrojích bývá označován termínem “implied global”. Jde o velice důležitou vlastnost jazyka, jejíž znalost (a hlavně plné pochopení důsledků) vám může ušetřit mnoho vytrhaných vlasů.

Continue reading