Co přináší nový ECMAScript 5? (dokončení)

Ve druhém dílu miniseriálu o připravované 5. edici ECMAScriptu se podíváme na další novinky, které tato specifikace přináší. Řeč bude především o nových funkcích pro práci s poli, podpoře JSON a striktním režimu vykonávání kódu.

Nové funkce pro práci s poli

Pro zacházení s poli jsou v ES3 k dispozici velmi omezené prostředky – když vynecháme zásobníkové, třídící a konverzní funkce, zjistíme, že pole jde v podstatě jen indexovat a je možné zjistit jeho délku. ES5 to napravuje a přidává do Array.prototype nové užitečné funkce, které umožňují s poli zacházet abstraktněji a ECMAScript trochu přibližují funkcionálnímu programování. Příznivci jazyků jako Lisp nebo Ruby některé z nich jistě poznají:

forEach
Aplikuje na každý prvek funkci předanou v parametru.
map
Aplikuje na každý prvek pole funkci předanou v parametru a z výsledků vytvoří nové pole.
filter
Vrátí nové pole obsahující prvky původního pole, jež prošly testovací funkcí předanou v parametru.
some
Zjistí, zda aspoň jeden prvek pole vyhovuje testovací funkci předané v parametru.
every
Zjistí, zda všechny prvky pole vyhovují testovací funkci předané v parametru.
reduce
Projde pole zleva doprava a aplikuje na každý prvek spolu s průběžným výsledkem (akumulátorem) funkci předanou v parametru. Iniciální hodnotu akumulátoru je možné explicitně zvolit, případně se použije první prvek pole.
reduceRight
Projde pole zprava doleva a aplikuje na každý prvek spolu s průběžným výsledkem (akumulátorem) funkci předanou v parametru. Iniciální hodnotu akumulátoru je možné explicitně zvolit, případně se použije poslední prvek pole.
indexOf
Vrátí index prvního výskytu daného prvku v poli, nebo –1, pokud se v něm prvek nevyskytuje. Je možné explicitně zvolit, od které položky začít hledání.
lastIndexOf
Vrátí index posledního výskytu daného prvku v poli, nebo –1, pokud se v něm prvek nevyskytuje. Je možné explicitně zvolit, od které položky začít hledání.

Využití

K čemu jsou uvedené funkce dobré? U některých je to zřejmé – forEach může nahradit klasické for-cykly, a indexOf spolu s lastIndexOf pomůžou při vyhledávání. Ale co třeba takové map, filter nebo reduce?

Představte si, že jste postaveni před následující problém: máte pole textů, z nichž chcete vybrat ty, které obsahují čísla, a tato čísla vynásobit. Klasické řešení bude v podobě funkce vypadat nějak takto:

function multiply(strings) {
  var result = 1; // neutrální prvek operace násobení
  for (var i = 0; i < strings.length; i++) {
    var numberValue = parseInt(strings[i]);
    if (!isNaN(numberValue)) {
      result *= numberValue;
    }
  }
  return result;
}

/* Příklad použití */
alert(multiply(["2", "3", "MCMLXXXII", "googol", "4"])); // vypíše "24" 

Uvedený kód sice funguje, ale není příliš hezký – jednotlivé fáze výpočtu jsou v něm zašmodrchané do sebe a v něm použito indexování spolu s několika pomocnými proměnnými. To vše vnáší do programu zbytečnou stavovost, ztěžuje porozumění kódu, jeho modifikaci a zvětšuje pravděpodobnost zavlečení chyb.

Tentýž problém lze vyřešit s využitím nových funkcí pro práci s poli:

function multiply(strings) {
  return strings
    .map(function(s) { return parseInt(s); })
    .filter(function(n) { return !isNaN(n); })
    .reduce(function(acc, n) { return acc * n; });
} 

Tato varianta je 2× kratší (4 vnitřní řádky funkce místo 8), lépe strukturovaná a je v ní snadněji vidět, co chtěl autor udělat. Daní je samozřejmě nutnost vědět, jak pracují nové funkce, a o něco menší efektivita výsledného kódu (ta ale v běžných případech nevadí).

Další informace

Pokročilé funkce pro práci s poli se poprvé objevily ve Firefoxu 1.5, dnes je ale implementují všechny prohlížeče kromě IE (výjimkou jsou funkce reduce a reduceRight, které jsou poměrně nové a jsou podporovány pouze ve Firefoxu, Safari a budou i v Chrome 2). Vzhledem k užitečnosti funkcí jsou některé z nich také často implementovány v javascriptových frameworcích (viz například rozšíření ArrayPrototype).

Další informace o nových funkcích pro práci s poli spolu s příklady můžete najít na příslušné stráncečeské mutaci vývojářského centra Mozilly.

Podpora JSON

Formát JSON jistě čtenářům není třeba představovat – slouží k uchovávání strukturovaných dat pomocí syntaxe, která je podmnožinou syntaxe JavaScriptu. Své využití má především v AJAXových aplikacích, kde často slouží k přenášení dat mezi klientskou a serverovou částí aplikace.

Problémem formátu JSON je jeho parsování. V současnosti se obvykle implementuje buď pomocí funkce eval, které se text v JSON předá jako parametr, nebo pomocí ručně napsaného parseru v JavaScriptu. První možnost má bezpečnostní rizika, druhá je zase pomalá. Z těchto důvodů přidává ES5 podporu práce s formátem JSON přímo do jazyka samotného.

Podporu JSON má na starost nový globální objekt JSON se dvěma funkcemi – parse a stringify. První z nich převede řetězec, který dostane jako parametr, z formátu JSON na javascriptový objekt. Druhá naopak umí z předaného javascriptového objektu vytvořit JSON řetězec. Obě funkce dovedou při serializaci/de­serializaci objektů provádět ještě různé transformace. Detaily jejich rozhraní si tu popisovat nebudeme, protože na Zdrojáku se o nich už psalo.

Kromě objektu JSON specifikace ještě definuje funkce toJSON pro typy String, Boolean, Number, a Date. Tyto funkce jsou využívány při serializaci objektů daných typů do JSON.

Nativní práci s JSON v současnosti podporuje pouze IE 8 (výjimečně je s něčím užitečným mezi prohlížeči úplně první), podpora je připravována i do Firefoxu 3.5 a Chrome 2. Další prohlížeče budou vzhledem k důležitosti JSON pravděpodobně brzy následovat.

Striktní režim

Nová edice ECMAScriptu zavádí striktní režim vykonávání kódu (strict mode). Ten především omezuje používání některých vlastností ECMAScriptu, které jsou častým zdrojem problémů a zpřísňuje kontrolu chyb. Mezi důležitá omezení striktního režimu patří:

  • zákaz používání příkazu with
  • zákaz přiřazení do nedeklarovaných proměnných (v běženém režimu takové přiřazení vytvoří novou globální proměnnou)
  • nemožnost definovat dvě či více vlastností objektu se stejným jménem v jednom objektovém literálu
  • nemožnost definovat dva či více parametrů funkce se stejným jménem
  • nemožnost mazat operátorem delete lokální proměnné či parametry funkce
  • omezení funkce eval (podrobněji níže)
  • omezení práce s objektem arguments a funkcemi (podrobněji níže)

Vyhovující implementace ECMAScriptu musí implementovat běžný i striktní režim jazyka. Musí také umožňovat spolupráci kódu spouštěného v různých režimech. Podrobný popis striktního režimu lze nalézt přímo ve specifikaci v dodatku C.

Zacházení s eval

Striktní režim poměrně zásadně omezuje zacházení s funkcí eval. Především kód uvnitř eval  nemůže při svém vykonávání ovlivňovat okolní lexikální prostředí (tj. například definovat nové lokální proměnné ve funkci, kde je eval volán). Není také možné vytvářet proměnné s názvem eval, ani do nich přiřazovat; podobně s parametry funkcí.

Uvedené změny jsou zřejmě motivovány výkonnostními optimalizacemi. Zajišťují, že funkce volající eval bude možné lépe optimalizovat a také že identifikátor eval bude vždy identifikovat jen tuto funkci a nebude nikdy předefinován. Proč bylo současné „volné“ chování problematické se můžete dočíst v článku věnovaném výkonnostně nepříjemným konstrukcím JavaScriptu.

Striktní režim a funkce

Ve striktním režimu se mění chování objektu arguments uvnitř funkcí. Především není možné přiřadit do identifikátoru s tímto jménem, což znamená, že identifikátor arguments bude vždy identifikovat jen objekt s parametry funkce. Vlastnosti arguments.caller a arguments.callee ve striktním režimu navíc vyvolají výjimku při přístupu. Dále jsou zakázány vlastnosti caller a arguments na instancích funkcí definovaných ve striktním režimu.

Podobně jako u evalu jsou uvedené změny pravděpodobně motivovány především výkonnostními optimalizacemi. Pro bližší pochopení problematiky opět doporučuji výše zmiňovaný článek o výkonnostně nepříjemných konstrukcích.

Zapínání a vypínání striktního režimu

Striktní režim je možné zapnout pro celý program nebo pro konkrétní funkci direktivou use strict umístěnou za začátku programu nebo funkce. Funkce definované v programu či funkci ve striktní režimu se stávají automaticky také striktními. Funkce si svou striktnost zachovávají, i když jsou zavolány z kódu v běžném režimu.

Direktiva use strict se (nejspíš z důvodů zpětné kompatibility) zapisuje poněkud zvláštně – jako řetězec:

function strictFunction() {
  "use strict";
  // a jsme ve striktním režimu
} 

Další informace

Striktní režim v podobě definované specifikací v současnosti žádný prohlížeč nepodporuje. Znalejší čtenáři si ale možná povšimli, že některá omezení striktního režimu jsou inspirována striktním režimem JavaScriptu ve Firefoxu.

Drobnosti

ECMAScript 5 přináší i mnoho menších změn a vylepšení. Některé důležitější z nich zmiňme aspoň telegraficky.

  • Nová funkce String.prototy­pe.trim sloužící k ořezání bílých mezer (whitespace) z okrajů řetězce. Tato funkce bude k dispozici ve Firefoxu 3.5 spolu se String.prototy­pe.trimLeft a String.prototy­pe.trimRight (ty v ES5 definovány nejsou).
  • Nová funkce Date.now vrací aktuální čas jako počet milisekund od začátku unixového světa (všichni jistě vědí, kdy to bylo). Funkci můžete využívat již dnes ve Firefoxu, Safari a Chrome.
  • Nová funkce Date.prototype­.toISOString převádí čas do formátu dle normy ISO 8601 („YYYY-MM-DDTHH:mm:ss.sssTZ“). Tento formát je využíván různými datovými formáty a přenosovými protokoly. Funkce bude k dispozici ve Firefoxu 3.5 a Chrome 2.
  • Literál regulárního výrazu doposud vytvářel jen jeden objekt při parsování a při každém následném průchodu kódem se pracovalo jen s referencí na něj. To bylo sice efektivní, ale mátlo to při operacích, které si v objektu regulárního výrazu uchovávaly stav (viz nejčastěji duplikovaný bug v javascriptovém interpretu Mozilly). ES5 nově definuje, že literál regulárního výrazu při každém průchodu vytvoří nový objekt.
  • Nový příkaz debugger slouží k vyvolání debuggeru, je-li program spuštěn v ladícím módu. Při běžném spuštění je příkaz ignorován.

Podrobný seznam všech změn oproti ECMAScriptu 3 s možným dopadem na kompatibilitu lze nalézt přímo ve specifikaci v dodatcích D a E.

Závěr

Jak je z obou článků miniseriálu vidět, změn v ES5 není úplně málo. Kromě getterů/setterů, zavedení striktního režimu a občasných oprav chyb se ale jedná jen o inkrementální vylepšení s minimálním vlivem na zpětnou kompatibilitu.

Vzhledem k tomu, že na vzniku specifikace se podíleli přímo výrobci prohlížečů, lze očekávat, že většina jejích novinek bude v dohledné době implementována – ostatně mnohé z nich už v některých prohlížečích dávno implementovány jsou. Osobně odhaduji, že nejdříve se univerzálně použitelné implementace dočká JSON, nejpozději pak funkce pro omezení práce s objekty jako Object.freeze a Object.seal.

Zda budou novinky reálně použitelné bude ale asi nejvíce záviset na Internet Exploreru, známé to brzdě vývoje webu. Jeho vývojáři se v posledních dvou verzích do vylepšování JavaScriptu nehrnuli, čemuž se nelze divit – ujížděl jim vlak na důležitějších frontách. Uvidíme, zda se jejich přístup s verzemi 9 a 10 změní.

Autor je vývojář se zájmem o programovací jazyky, webové aplikace a problémy programování jako takového. Vystudoval informatiku na MFF UK a během studií zde i trochu učil. Aktuálně pracuje v SUSE.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 2

Přehled komentářů

kuku Trim
Mazarik Re: Trim
Zdroj: https://www.zdrojak.cz/?p=3014