W ostatnim poście Wprowadzenie do ECMAScript 5 cz. 1 omówiliśmy atrybut rozszerzalności obiektów oraz deskryptory własności, w tej części przyjrzymy się reszcie nowości z piątego wydania ECMAScript.

Rozszerzenia w konstruktorze ArrayR

Array.isArray(obj) – zwraca true jeśli obj jest tablicą, false w przeciwnym razie. Poprawna implementacja tej funkcji przed ECMAScript 5 była dość nieelegancka.

Nowe funkcje w Array.prototype:

indexOf(p [, start]) – zwraca najniższy indeks elementu, dla którego element === p jest true

lastIndexOf(p [, start]) – zwraca najwyższy indeks elementu, dla którego element === p jest true

every(func [, o]) – zwraca true, jeśli funkcja func zwróci true dla wszystkich elementów tablicy

 var a = [1, 2, 3, 4];
a.every(function(x) { return x > 0; } );   // zwraca true

some(func [, o]) – zwraca true, jeśli funkcja func zwróci true dla dowolnego elementu tablicy

 var a = [1, 2, 3, -5];
a.some(function(x) { return x < 0; }); // zwraca true

forEach(func [, o]) – wykonuje funkcję func na każdym elemencie tablicy

map(func [, o]) – zwraca nową tablicę zawierającą elementy zwrócone przez funkcję func, która została wykonana na wszystkich elementach tablicy.

var a = [1, 2, 3];
a.map(function(x) { return x*x; }); // zwraca [1, 4, 9]

filter(func [, o]) – zwraca nową tablicę zawierającą elementy, dla których func zwróciło true

 var a = [1, -1, 2, -2, 3, -3];
a.filter(function(x) { return x > 0; }); // returns [1, 2, 3]

reduce(func [, initial]) – zwraca wartość wyliczoną z elementów tablicy przy pomocy funkcji func. Func jest wykonywana kolejno na ostatniej zwróconej przez nią wartości i kolejnym elemencie z tablicy. Pierwsze wywołanie następuje na dwóch pierwszych elementach tablicy, chyba że podany jest parametr initial, wtedy pierwsze wywołanie wykonane jest na parze (initial, pierwszy element tablicy)

 var a = ['a', 'b', 'c', 'd'];
a.reduce(function(a, b) { return a + b; });    // zwraca "abcd" 
a.reduce(function(a, b)  { return a + b + ':'; }, ':');    // zwraca ":a:b:c:d:"

reduceRight(func [, initial]) – analogiczna funkcja do reduce, różnica polega na tym, że redukcja następuje od prawej do lewej (rozpoczynając od ostatniego elementu tablicy).

 var a = ['a', 'b', 'c', 'd'];
a.reduceRight(function(a, b) { return a + b; });     // returns "dcba"

Obiekt JSON

Obiekt JSON umożliwia szybką (natywną) i bezpieczną serializację oraz deserializację stringów w formacie JSON do obiektów ECMAScript i w drugą stronę. Obiekt ten udostępnia tylko dwie funkcje: stringify oraz parse. Stringify serializuje obiekty JavaScript do stringa w formacie JSON, funkcja parse robi dokładnie odwrotnie. Obie funkcje posiadają opcjonalne parametry, które umożliwiają filtrowanie oraz transformacje wybranych własności obiektów.

Strict mode

Funkcjonalność strict mode, po włączeniu, ustawia engine JavaScript w tryb, w którym Twój kod będzie poddany bardziej rygorystycznym regułom zarówno pod względem syntaktycznym (składni) jak i semantycznym (wykonania). Większość popularnych pomyłek, które do tej pory były ignorowane, będzie zgłaszanych w tym trybie jako błędy. Np. przypisywanie wartości do niezadeklarowanej wcześniej zmiennej było do tej pory zupełnie akceptowalne (z perspektywy interpretera/kompilatora), w trybie strict mode takie zachowanie powoduje wyjątek ReferenceError.

Włączanie trybu rygorystycznego (strict mode) zostało zaprojektowane w ten sposób, aby nowy kod, używający tego trybu działał zupełnie poprawnie na wcześniejszych wersjach kompilatorów nie wspierających ECMAScript 5.

Aby włączyć strict mode, wystarczy w kodzie umieścić:

 "use strict";

na początku pliku (przed jakimikolwiek innymi instrukcjami) jeśli chcemy włączyć go dla całego pliku. Możemy też umieścić aktywator na początku funkcji aby włączyć strict mode tylko dla funkcji.

Dokładne reguły trybu strict mode są bardzo dobrze opisane w artykule na Mozilla Developer Network. Warto tam zajrzeć.

Function.prototype.bind

W języku JavaScript wiązanie funkcji do obiektu jest operacją tymczasową, wykonywaną w momencie wywołania funkcji. Wiązanie do obiektu nie jest permanentną własnością funkcji i zależy od kontekstu danego wywołania. Najlepiej zobrazować to na przykładzie:

 // definiujemy prostą funkcję
var f = function() { console.log(this); }

// tworzony obiekt i przypisujemy f do własności func tego obiektu
var obj = { func: f };

// wywołujemy funkcję f na trzy różne sposoby
f();                        // wypisze do konsoli  obiekt  window (wiązanie do obiektu globalnego)
obj.func();          // wypisze do konsoli obiekt obj (wiązanie do obiektu obj)
var o = new f();  // wypisze do konsoli zupełnie nowo utworzony obiekt, który jest następnie zwrócony

// wiązanie funkcji jest operacją tymczasową
var some_func = obj.func; 
some_func();    // znowu wypisze obiekt window (wiązanie do obiektu globalnego)

Mając do dyspozycji funkcję bind, możemy utworzyć permanentne wiązanie funkcji do obiektu. Dodatkowo możemy wykonać częściową aplikację funkcji (currying):

 var bound_f = f.bind(obj);
bound_f();   // wypisze obj pomimo że wywołujemy ją nie w kontekście obiektu obj

Częściowa aplikacja funkcji:

 var add = function(a, b) { return a + b; };
var inc = add.bind(undefined, 1);
var dec = add.bind(undefined, -1);
inc(4);   //  5
dec(4);  //  3

Zarówno wiązanie do obiektu jak i częściową aplikację można w łatwy sposób osiągnąć w ECMAScript 3 przy pomocy domknięć (closure), bind jest zatem tylko dodatkiem typu syntactic sugar.

Wszystkich, którzy chcieliby poznać więcej szczegółów na temat ECMAScript 5 zachęcam do lektury MDN JavaScript reference.