Scott Tiger Tech Blog

Blog technologiczny firmy Scott Tiger S.A.

ECMAScript 6 (Harmony)

Autor: Piotr Karpiuk o wtorek 17. Lipiec 2012

W jednym z poprzednich postów opisałem wdrożony już w życie w najnowszych przeglądarkach WWW standard ECMAScript 5. Tymczasem od dłuższego czasu trwają już prace nad wersją 6 o nazwie kodowej Harmony. Specyfikacja ma być gotowa z końcem 2013 roku, ale pomimo że jeszcze wszystko może się jeszcze zmienić Google i Mozilla już wyskakują przed szereg i np. Google w wersji 19 swojej przeglądarki Chrome pozwala odważnym użytkownikom włączyć flagę Experimental JavaScript features dostępną pod URLem chrome://flags.

Już teraz wiadomo, że wersja 6 ECMAScriptu ma być najbardziej wszechstronną aktualizacją w historii języka. Ogólne wytyczne:

  • język ma być przyjazny dla przypadkowych programistów,
  • ma nadawać się do tworzenia większych aplikacji i bibliotek,
  • ma zawierać syntaktyczne udogodnienia dla dobrych wzorców abstrakcji,
  • standard ma zatwierdzać powszechnie stosowane rozwiązania (standardy de facto).

Google Chrome

A oto co mamy już zaimplementowane w Google Chrome 19, więc z dużym prawdopodobieństwem przetrwa próbę czasu:

let i const

Jak do tej pory, jedynym zakresem zmiennych był zakres funkcji, co nieraz skutkowało tworzeniem dziwnych konstrukcji w rodzaju:

        function() {
          var zmienna;
          ...
        }();

tylko po to, aby ograniczyć zasięg zmiennych.

Innym problemem był brak możliwości deklarowania stałych.

Oba te problemy rozwiązują konstrukcje let (deklaracja zmiennej) i const (deklaracja stałej), które działają podobnie jak var ale mają zasięg bloku, a zmienna zadeklarowana jako const nie może być modyfikowana.

Kolekcje

Nie trzeba już mylić pustego obiektu z pustą mapą, bo są dostępne nowe klasy Map i Set. Kluczami mapy i elementami zbioru mogą być dowolne obiekty – w przypadku typów prostych porównywane będą wartości, a w przypadku obiektów będzie używana metoda Object.is( x, y ), która z grubsza odpowiada operatorowi === (tożsamość).

        var m = new Map();
        m.set( 1, 'bar' );
        m.has( 1 ); // true
        m.get( 1 ); // 'bar';
        m.delete( 1 );

        var s = new Set();
        s.add( 2 );
        s.has( 2 ); // true
        s.delete( 2 );

Według specyfikacji (ale póki co nie zaimplementowane w Chrome) w słowniku powinna być metoda keys() zwracająca tablicę kluczy, a w obu typach kolekcji metody values() (zwracają tablice wartości) oraz iterate(callback, context), gdzie callback przyjmuje parametry context, value, key dla słownika i context, value, index dla zbioru.

Dość ciekawym nowym zaimplementowanym typem jest WeakMap, który ma następujące własności:

  • kluczami mogą być wyłącznie obiekty (w odróżnieniu od wartości prostych),
  • nie jest wyliczalny (ang. enumerable) i nie podlega introspekcji,
  • jeśli klucz nie jest osiągalny, to para klucz-wartość może zostać usunięta z mapy przez mechanizm odśmiecania (ang. garbage collector).

Pełnomocnicy (ang. proxies)

Pełnomocnik to abstrakcja wirtualizowanego obiektu, czyli obiekt z dołączonym handlerem będącym w stanie przechwycić wszelkie interakcje z obiektem, takie jak odczyt/zapis własności czy wywołanie metody. Jest to bardzo przydatna technika do ukrycia szczegółów implementacji takich pojęć jak:

  • trwałe obiekty (ang. persistent objects), czyli zapisujące swój stan w pamięci zewnętrznej,
  • obiekty zdalne (ang. remote objects),
  • leniwe tworzenie obiektów,
  • logowanie/profilowanie wywoływanych metod,
  • dynamiczne przechwytywanie brakujących metod,
  • baza dla własnych iteratorów.

Możliwe jest również utworzenie pełnomocnika dla funkcji, tzn. przechwycenie zdarzenia wywołania funkcji i wyrażenia new.

Niestety, ostateczny kształt tego aspektu języka najwyraźniej jeszcze się nie wykrystalizował. Google Chrome ma zaimplementowane tzw. old proxies, które aktualnie są w specyfikacji zastąpione przez direct proxies. Chętnym do zabawy starą koncepcją polecam tutorial.

Firefox

W dostępnej w Internecie rozpisce dowiadujemy się, że Firefox ma zaimplementowane kolekcje podobnie jak Chrome, a także tzw. rest parameters, czyli możliwość eleganckiego tworzenia funkcji ze zmienną liczbą parametrów. Ponadto zaimplementował kilka innych mechanizmów aktualnie niezgodnych ze specyfikacją, bo się w międzyczasie zmieniła.

Zmienna liczba parametrów funkcji

Funkcję JavaScriptu można niezależnie od liczby parametrów formalnych śmiało wykonać z dowolną liczbą parametrów – wszystkie parametry aktualne dostępne są wewnątrz funkcji za pomocą specjalnej zmiennej arguments, która wszakże nie jest prawdziwą tablicą (nie ma wielu metod w rodzaju sort, forEach itp.). Stąd dość często stosuje się sztuczkę:

        function f(a, b){
          var args = Array.prototype.slice.call(arguments, 2);
          // ...
          }

W zmiennej args mamy prawdziwą tablicę nadmiarowych parametrów aktualnych. ECMAScript 6 definiuje lukier syntaktyczny na tę okoliczność, tzn. pozwala napisać:

        function f(a, b, ...args){
          // ...
        }

Pozostałe nowości

Aby wyrobić sobie zdanie o ECMAScript 6, przyjrzyjmy się pozostałym, niezaimplementowanym jeszcze poprawnie w żadnej przeglądarce nowościom, które wydają się być już pewne.

Parametry domyślne

        function f( x = 10, y = 15 ) { ... }

Operator rozszczepiania (ang. spread operator)

        let arr = [0,1,2,3];
        let obj = new MyConstructor(57, ...a); // to samo co new MyConstructor(57, 0, 1, 2, 3)

Destructuring

        [a, b] = [b, a]; // zamiana wartości miejscami
        
        function f() { return [1, 2, 3] }
        var a, b, c;
        [a, b, c] = f(); // zwracanie wielu wartości
        var [a, , b] = f(); // niektóre wartości nie są potrzebne

        function panel( { title: title, pos: [x, y] } ) {
          return title + x + y;
        }
        panel( { title: "Users", pos: [10, 15] } );
        
        for ( let [name, value] in obj ) { ... }

        for each ( let { name: n, family: { father: f } } in obj ) {
          print("Name: " + n + ", Father: " + f);
        }

Moduły i klasy

        module NewMath {
          var n = 0;
          export function increment() { return n++ }
          export var pi = 3.141593;
          export module alert { ... }  // zagnieżdżony moduł
        }

        import * from NewMath;

        class SkinnedMesh extends THREE.Mesh {
          constructor(geometry, materials) {
            super(geometry, materials);

            public identityMatrix = new THREE.Matrix4();
            public bones = [];
            public boneMatrices = [];
            ...
          }

          update(camera) {
            ...
            super.update();
          }
        }

Generatory

        function fibonacci() {
          let [prev, curr] = [0, 1];
          while( true ) {
            [prev, curr] = [curr, prev+curr];
            yield curr;
          }
        }

        for( let n in fibonacci() ) {
          console.log( n );
        }

Iteratory

        function iterator( object ) {
          for( let k in object ) {
            yield [k, object[k]];
          }
        }

        var obj = { x: 10, y: 20 };
        for( let [k,v] in iterator( obj ) ) {
          console.log( k, v );
        }

Listy składane (ang. array comprehensions)

        let scores = [1, 7, 4, 9].
          filter( function( x ) { retrun x > 5; }.
          map( function( x ) { return x * x; }); // [49, 81]

        // Lista składana, która robi to samo:
        let scores = [ x * x for (x in values( [1, 7, 4, 9])) if ( x > 5 )];

Rozszerzenia klas Math i String

W klasie Math proponuje się dodać funkcje sign, log10, log2, log1p (naturalny logarytm z 1+x), cosh, sinh, tanh, acosh, asinh, atanh, hypot, trunc.

Nowe metody klasy String prezentują przykłady:

        "*".repeat( 10 ); // '**********'
        'Jasio'.startsWith( 'Ja' ); // true
        'Jasio'.endsWith( 'siu' ); // false
        'Jasio'.contains( 'a' ); // true
        'Jasio'.toArray(); // ['J', 'a', 's', 'i', 'o']

Share and Enjoy:
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Śledzik
  • Blip
  • Blogger.com
  • Gadu-Gadu Live
  • LinkedIn
  • MySpace
  • Wykop

Zostaw komentarz

XHTML: Możesz użyć następujących tagów: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>