Přejít k navigační liště

Zdroják » Různé » ECMAScript 5.1

ECMAScript 5.1

Články Různé

ECMAScript 5.1 (ES5.1) je poslední verzí ECMAScriptu, standardu, na kterém je postaven JavaScript. Podobně jako u HTML5 je i ES5 standardizací existujících implementací a rozšíření jazyka. Jednou z nich je například strict mode, o němž jsme už psali. V článku si představíme některé další novinky verze 5.1.

Překlad článku Introducing ECMAScript 5.1 (autor: Mike Taylor) z webu Dev.Opera. Překlad vychází s laskavým svolením Opera Software.

Úplný seznam novinek naleznete v přílohách D a E v oficiální specifikaci ECMAScriptu (PDF) na webu http://www.ec­mascript.org/;  v HTML podobě jej najdete na stránkách Michael[tm] Smith’s unofficial annotated HTML version.

Podpora ES5.1 v prohlí­žečích

S vydáním Opery 11.60 je ES5 podporován ve všech pěti hlavních prohlížečích. Pokud nebude řečeno jinak, budou všechny dále zmiňované vlastnosti dostupné v těchto verzích (a vyšších):

  • Opera 11.60
  • Internet Explorer 9*
  • Firefox 4
  • Safari 5.1**
  • Chrome 13

* IE9 zatím nepodporuje strict mode, až ve verzi IE10.

** V Safari 5.1 stále není podpora pro Function.prototype.bind, ačkoli před nedávnem byla přidána do Webkitu .

Stav podpory ve starších prohlížečích naleznete na stránce ECMAScript 5 compatibility table od Jurije Zajceva (Juriy Zaytsev).

Strict Mode v ES5

Strict mode (viz ECMAScript Strict mode ve Firefoxu 4) je způsob, jakým se vývojář může přihlásit k restriktivnější verzi jazyka, která přináší vyšší bezpečnost a spolehlivost. Strict mode je nastaven přidáním direktivy "use
strict";
na začátek souboru nebo funkce. Protože je tato direktiva prostý řetězec, bude bez problémů staršími prohlížeči ignorována.

"use strict";
function strict(){
  "use strict";
  //...
}

function sloppy(){
  eval("window.foo = 'bar'");
}

Mnoho věcí, které v normálním JavaScriptu způsobí nepředvídatelné chybné chování, způsobí ve strict mode výjimku, kupříkladu:

  • Přiřazení do nedeklarované proměnné vyhodí ReferenceError (v prostém JS vytvoří globální proměnnou).
  • Vícenásobné přiřazení do stejně pojmenované vlastnosti v objektovém zápisu vyvolá  SyntaxError.
  • Byla odstraněna konstrukce with. Její použití vyvolá  SyntaxError.

Pěkné shrnutí těchto rozdílů naleznete v článku na MDSN.

JSON

ES5 zavádí globální objekt JSON, který slouží k serializaci ( JSON.stringify) a deserializaci ( JSON.parse) objektů do/z formátu JSON.

U starších prohlížečů lze použít polyfill skript json2.js od Douglase Crockforda, který poskytuje stejnou funkčnost (samosebou nejprve otestuje nativní podporu).

JSON.parse(text [, reviver])

JSON.parse bere řetězec (ve formátu JSON) a vrací hodnotu. Volitelný parametr reviver je funkce s dvěma argumenty, key a value, která je provedena nad výsledky, což je umožňuje filtrovat a měnit před tím, než jsou vráceny.

>> var result = JSON.parse('{"a": 1, "b": "2"}');
Object

>> result.b
"2"

Pokud se chceme ujistit, že výsledkem bude celé číslo (nikoli řetězec), použijeme tuto funkci.

var result = JSON.parse('{"a": 1, "b": "2"}', function(key, value){
  if (typeof value == 'string'){
    return parseInt(value);
  } else {
    return value;
  }
})

>> result.b
2

JSON.stringify(value [, replacer [, space]])

JSON.stringify bere hodnotu a převádí ji na řetězec ve formátu JSON. V nejjednodušší podobě přebírá jednu hodnotu a vrací řetězec.

>>> var mike = JSON.stringify({mike: "taylor"})
undefined

>> mike
'{"mike": "taylor"}'

>> typeof mike
"string"

Když potřebujeme změnit způsob, jakým je hodnota převedena na řetězec, nebo filtrovat data, můžeme předat funkci replacer. Kupříkladu pokud chceme vynechat hodnotu 13, můžeme to provést takto:

var nums = {
  "first": 7,
  "second": 14,
  "third": 13
}

var luckyNums = JSON.stringify(nums, function(key, value){
  if (value == 13) {
    return undefined;
  } else {
    return value;
  }
});

>> luckyNums
'{"first": 7, "second": 14}'

Pokud funkce replacer vrátí hodnotu  undefined, nebude tento klíč ve výsledném JSON zahrnut. Třetím argumentem je počet mezer, kterým se má odsadit zanoření (kvůli lepší čitelnosti výsledného textu), nebo řetězec, který je přidán jako výplň odsazování. Hodnoty větší než 10 jsou převedeny na 10, řetězec delší než 10 znaků je oříznut a je použito pouze prvních deset znaků.

var luckyNums = JSON.stringify(nums, function(key, value) {
  if (value == 13) {
    return undefined;
  } else {
    return value;
  }
}, 2);

>> luckyNums
'{
  "first":7,
  "second":14
}'

Rozšíření Object

Ke konstruktoru  Object byly přidány následující metody:

  • Object.getPrototypeOf
  • Object.getOwnPropertyDescriptor
  • Object.getOwnPropertyNames
  • Object.create
  • Object.defineProperty
  • Object.defineProperties
  • Object.seal
  • Object.freeze
  • Object.preventExtensions
  • Object.isSealed
  • Object.isFrozen
  • Object.isExtensible
  • Object.keys

Jednou z výhod je lepší řízení práce s vlastnostmi objektu, např. určení, které lze měnit, procházet, mazat apod. Tyto možnosti se nastavují pomocí tzv. property deskriptorů. Kupříkladu:

var cat = {};

Object.defineProperty(cat, "name", {
  value: "Maru",
  writable: false,
  enumerable: true,
  configurable: false
});

Object.defineProperty(cat, "skill", {
  value: "exploring boxes",
  writable: true,
  enumerable: true,
  configurable: true
});

U našeho objektu cat nelze měnit vlastnost name, ale objeví se při procházení smyčkou  for-in (enumerable). Kromě jiného je Maru dobrá v prozkoumávání krabiček, ale tato schopnost může být v budoucnu změněná, tak má vlastnost skill ponechané příznaky writableconfigurable.

V některém z dalších článků se k těmto vlastnostem vrátíme.

Vylepšení polí

K prototypu Array byly přidány následující možnosti:

  • Array.prototype.indexOf
  • Array.prototype.lastIndexOf
  • Array.prototype.every
  • Array.prototype.some
  • Array.prototype.forEach
  • Array.prototype.map
  • Array.prototype.filter
  • Array.prototype.reduce
  • Array.prototype.reduceRight

Dmitrij Šošnikov (Dmitry Soshnikov) napsal podrobný článek o těchto rozšířeních polí v ES5.

Jedna metoda, kterou Dmitrij v článku nezmínil, je Array.isArray, která je přidána přímo ke konstruktoru, nikoli k prototypu.  Array.isArray dělá to, co od něj očekáváme – je to metoda, která vrátí  true nebo false podle toho, jestli vnitřní vlastnost [[Class]] je rovna „Array“.

Array.isArray("NO U")
>> false

Array.isArray(["NO", "U"])
>> true

V ES3 byl jediný použitelný způsob, jak určit, zda je hodnota pole nebo ne, takzvaný „the Miller Device“, neboli porovnání interní vlastnosti [[Class]] s tou, kterou má pole.

Object.prototype.toString.apply(value) === '[object Array]'

Function.prototype.bind(thisArg [, arg1 [, arg2, …]])

Function.prototype.bind vrací novou funkci, u níž je hodnota this nastavena podle argumentu thisArg. To umožňuje vykonat funkci v kontextu jiného objektu

function locate(){
  console.log(this.location);
}

function Maru(location){
  this.location = location;
}

var kitty = new Maru("cardboard box");

var locateMaru = locate.bind(kitty);

locateMaru();

V tomto příkladu voláme funkci location v kontextu objektu Maru. Protože locate je vlastností globálního objektu, je v něm this rovno právě globálnímu objektu ( window). V našem případě hledáme kočku, nikoli objekt Location, takže si vytvoříme novou funkci locateMaru, kde je hodnota this svázána s  kitty.

Další zdroje informací

Komentáře

Subscribe
Upozornit na
guest
12 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
dmkil

Vdaka za clanok. V kombinacii s dojotoolkit-om a html5 mame uz v rukach solidne standardy na strane weboveho klienta. Este implementovat niektore dolezite akcie nad img: hlavne vyrez.

alancox

Jen dotaz, odkdy je HTML5 standardem?

Že by mi něco ušlo a HTML5 by měl svůj závazný jasně určený betonově stabilní standard?

Považuji HTML5 do doby, než vyjde závazný a konečný popis hotového standardu za cokoli jen ne za standard.

Pavel Křivánek

JavaScriptu dost citelně (a nepochopitelně) chybí nativní funkce pro vytvoření mělké kopie objektu. Kopírování přes výčet vlastností je šíleně pomalé.

Aichi

Kolikrat do roka takovou kopii potrebujes? Jinak samozrejme ty funkce tam jsou, ale jmenuji se jinak ;)

function copy(objToCopy) {
return JSON.parse(JSON­.stringify(ob­jToCopy));
}

Pavel Křivánek

To je potřeba v jednom kuse :-) Tahle operace je přeci pro prototypový jazyk naprostý základ. To se pak člověk nestačí divit, když nahodí profiler a zjistí, že mu taková blbost, jako kopírování objektů zabere třetinu času :-) Dnes je nejrychlejší si vytvořit funkci, ve které se ručně přehází všechny prvky objektu.

Nehledě na to, že z hlediska zapouzdření by se měla (obecná) kopie objektu dělat tak, že si objekt vytvoří svoji mělkou kopii a té se pak zavolá něco jako postCopy, čímž si kopie objektu sama vytvoří hlubší kopii vybraných prvků bez toho, aby mezi původním objektem a jeho kopií musela probíhat nějaká další komunikace.

asdasd

Pěkný řešení, ale nebude fungovat všude. Tohle je z hlediska kompatibility o něco lepší trik:

Copy = function() {};
copy = function(object) {
    Copy.prototype = object;
    return new Copy();
};
Pavel Lang

no, nápad dobrej, ale ještě by to chtělo asi uzavřít do closure:

/* protoCopy - copy není přesně... */
var protoCopy = function(obj) {
    var f = function() { };
    f.prototype = obj;
    return new f();
};

Stejně by mě ale zajímalo, jak tohle bude fungovat; prototype.prototype se určitě procházet nebude, takže to stejně asi není (dobré) řešení na všechno

asdasd

Tvoje verze je o něco elegantnější, ale náročná na paměť, která se bude ukusovat s každým voláním. Původní verze by šla přepsat tak, že funkce copy bude používat sama sebe:

copy = function(object) {
    if (arguments.length) {
        var copy = arguments.callee;
        copy.prototype = object;
        return new copy();
    }
};
BS-Harou

Když už jsme u toho ES5, nešlo by jednoduše použít tohle:

function copy(object) {
    return Object.create(object);
}

Tak jako tak ale může vzniknout problém s hasOwnProperty na tomto novém objektu.

Pavel Křivánek

Ne, tato funkce vytváří objekt s daným prototypem a vlastnostmi, nikoliv jeho kopii.

var o1 = {a: 1, b: 2};
var o2 = Object.create(o1);
o1.a = 3;
alert(o2.a) // vysledek je 3

Pavel Křivánek

Tato funkce nevytváří skutečnou mělkou kopii objektu, používat ji za tímto účelem může vést k velmi zapeklitým chybám.

Copy = function() {};
copy = function(object) {
    Copy.prototype = object;
    return new Copy();
};


var o1 = {a: 1, b: 2};
var o2 = copy(o1)
o1.a = 3;
alert(o2.a) // == 3
asdasd

To je vlastně pravda. Ještě by to šlo takhle :-)

o1 = {a: 1, b: 2};

o2 = copy(o1);
o1 = copy(o1);

o1.a = 3;
alert(o2.a); // == 1

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.