Apply your JS skills to key Mozilla projects as an MDN Fellow! http://mzl.la/MDNFellowship

mozilla
Wyniki wyszukiwania

    Nowości w JavaScript 1.7

    UWAGA: Tłumaczenie tej strony nie zostało zakończone.
    Może być ona niekompletna lub wymagać korekty.
    Chcesz pomóc? | Dokończ tłumaczenie | Sprawdź ortografię | Więcej takich stron+.
    JavaScript 1.7 jest aktualizacją języka wprowadzającą kilka nowych funkcji, w szczególności generatory, iteratory, uproszczenia składni dla tablic, wyrażenia let, oraz rozpakowywanie struktur. Obsługuje również wszystkie nowe funkcje JavaScript 1.6.

    JavaScript 1.7 jest obsługiwany począwszy od Firefoksa 2.0 beta 1 i kolejne oraz wersje "nightly" z gałęzi "trunk".

    Przykłady znajdujące się w tym artykule mogą być wypróbowane w powłoce JavaScript. Przeczytaj Wprowadzenie do powłoki JavaScript, aby nauczyć się jak kompilować i używać tą powłokę.

    Użycie JavaScript 1.7

    Aby używać nowych funkcji JavaScriptu 1.7, musisz określić, że chcesz używać właśnie tej wersji. W pliku HTML lub XUL użyj:

    <script type="application/javascript;version=1.7"/>
    

    Jeśli pracujesz w powłoce JavaScript , musisz określić wersję, której chcesz użyć poprzez funkcję version():

    version(170);
    

    The features that require the use of the new keywords "yield" and "let" require you to specify version 1.7 because existing code might use those keywords as variable or function names. The features that do not introduce new keywords (destructuring assignment and array comprehensions) can be used without specifying the JavaScript version.

    Generatory i iteratory

    Podczas pisania kodu, który zawiera algorytmy iteracyjne (takie jak iteracja listy, albo powtarzane wykonywanie obliczeń na zestawie danych), często używane są zmienne stanu, których wartości są potrzebne na czas trwania obliczeń. Dotychczas, trzeba było ustawić funkcję zwrotną, która obsłuży pośrednie wartości algorytmu iteracyjnego.

    Generatory

    Rozważmy ten algorytm iteracyjny, który tworzy liczby Fibonacciego:

    function do_callback(num) {
      document.write(num + "<br>\n");
    }
    
    function fib() {
      var i = 0, j = 1, n = 0;
      while (n < 10) {
        do_callback(i);
        var t = i;
        i = j;
        j += t;
        n++;
      }
    }
    
    fib();
    

    Ten kod używa funkcji zwrotnej do wykonania operacji w każdym kolejnym kroku algorytmu. W tym przypadku, każdy numer Fibonacciego jest po prostu wyświetlany na konsoli.

    Generatory i iteratory współpracują dając nowy, lepszy sposób na wykonanie tego. Zobaczmy jak to będzie wyglądało przy użyciu generatora:

    function fib() {
      var i = 0, j = 1;
      while (true) {
        yield i;
        var t = i;
        i = j;
        j += t;
      }
    }
    
    var g = fib();
    for (var i = 0; i < 10; i++) {
      document.write(g.next() + "<br>\n");
    }
    

    Funkcja posiadająca słowo kluczowe yield jest generatorem. Kiedy ją wywołasz, jej parametry zostają powiązane z argumentami, ale ciało funkcji nie jest wykonywane. Zamiast tego, zwracana jest para generator-iterator. Każde wywołanie metody next() tego generatora-iteratora wykonuje kolejny cykl iterowanego algorytmu. Wartość każdego kroku jest wartością zmiennej określonej słowem kluczowym yield. Myśl o yield jak o return w modelu generatora-iteratora, zwracającym wartość każdej iteracji algorytmu. Za każdym razem gdy wywołujesz next(), kod generatora zostaje uruchomiony od linii następującej po wyrażeniu yield.

    Iteracja przez generator-iterator jest wykonywana poprzez wielokrotne wywoływanie metody next(), dopóki nie osiągniesz potrzebnego wyniku. W tym przypadku, możemy otrzymać liczby Fibonacciego, kontynuując wywoływanie g.next(), aż dostaniemy tyle wyników ile chcemy.

    Resuming a generator at a specific point

    Once a generator has been started by calling its next() function, you can use send(), passing a specific value that will be treated as the result of the last yield. The generator will then return the operand of the subsequent yield.

    You can't start a generator at an arbitrary point; you must start it with next() before you can send() it a specific value.

    Note: As a point of interest, calling send(undefined) is equivalent to calling next(). However, starting a newborn generator with any value other than undefined when calling send() will result in a TypeError exception.
    Exceptions in generators

    You can force a generator to throw an exception by calling its throw() method, passing the exception value it should throw. This exception will be thrown from the current suspended context of the generator, as if the yield that is currently suspended were instead a throw value statement.

    If a yield is not encountered during the processing of the thrown exception, then the exception will propagate up through the call to throw(), and subsequent calls to next() will result in StopIteration being thrown.

    Closing a generator

    Generators have a close() method that forces the generator to close itself. The effects of closing a generator are:

    1. Any finally clauses active in the generator function are run.
    2. If a finally clause throws any exception other than StopIteration, the exception is propagated to the caller of the close() method.
    3. The generator terminates.
    Generator Example

    This code drives a generator that will yield every 100 loops.

    var gen = generator();
    
    function driveGenerator() {
    	if (gen.next()) {
    		window.setTimeout(driveGenerator, 0);	
    	} else {
    		gen.close();	
    	}
    }
    
    function generator() {
    	while (i < something) {
    		/** stuff **/
    
    		++i;
    		/** 100 loops per yield **/
    		if ((i % 100) == 0) {
    			yield true;
    		} 
    	}
    
    	yield false;
    }
    

    Iteratory

    Iterator jest specjalnym obiektem, który pozwala Ci iterować się przez dane.

    W normalnym użyciu, obiekty iteratora są "niewidzialne"; nie jest konieczne bezpośrednie operowanie na nich. Zamiast tego, możesz użyć JavaScriptowego wyrażenia for...in oraz for each...in, by pobrać wszystkie klucze i/lub wartości obiektów.

    var obiektZIteratorem = getObjectSomehow();
    
    for (var i in obiektZIteratorem)
    {
      document.write(obiektZIteratorem[i] + "<br>\n");
    }
    

    Jeżeli implementujesz swój własny obiekt iteratora, lub masz inne potrzeby dotyczące bezpośredniego manipulowania iteratorami, prawdopodobnie będziesz chciał się zapoznać z metodą next, wyjątkiem StopIteration oraz metodą __iterator__.

    Możesz stworzyć iterator dla dowolnego obiektu wywołując Iterator(nazwaobiektu); iterator obiektu jest znajdywany poprzez wywołanie metody __iterator__. Jeśli metoda __iterator__ nie występuje tworzony jest domyślny iterator. Wywołuje on własności obiektu zgodnie ze zwykłym modelem używanym w wyrażeniach for...in i for each...in. Jeżeli chcesz dodać własny iterator, powinieneś przeciążyć metodę __iterator__, aby zwracała instancję Twojego własnego iteratora. Aby pobrać iterator obiektu ze skryptu, lepiej jest użyć Iterator(obj) niż pobierać bezpośrednio własność __iterator__.Pierwszy działa z Arrays; drugi nie.

    Kiedy masz już iterator, możesz z łatwością pobierać następny element z obiektu wywołując jego metodę next(). Jeśli w obiekcie nie ma już więcej elementów, zostanie zwrócony wyjątek StopIteration.

    Prosty przykład bezpośredniej manipulacji iteratorem:

    var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};
    
    var it = Iterator(obj);
    
    try {
      while (true) {
        document.write(it.next() + "\n");
      }
    } catch (err if err instanceof StopIteration) {
      document.write("Koniec rekordu.\n");
    } catch (err) {
      document.write("Nieznany błąd: " + err.description + "\n");
    }
    

    Wynik działania programu wygląda tak:

    name,Jack Bauer
    username,JackB
    id,12345
    agency,CTU
    region,Los Angeles
    End of record.
    

    Możesz, opcjonalnie, określić drugi parametr przy tworzeniu swojego iteratora, typu boolean, który określa czy chcesz tylko zwracać klucze jako wynik metody next(), czy także wartości. Zmiana var it = Iterator(obj); na var it = Iterator(obj, true); w powyższym przykładzie zmienia wynik na następujący:

    name
    username
    id
    agency
    region
    End of record.
    

    W obu przypadkach, kolejność w jakiej zwracane są dane jest zależna od implementacji. Nie ma żadnej gwarancji, że dane zostaną zwrócone w takiej kolejności.

    Iteratory są wygodną metodą do skanowania danych w obiektach, włączając w to obiekty, które mogą zawierać dane, o których nie wiesz. Jest to szczególnie przydatne, jeśli musisz zachować dane, których Twoja aplikacja może się nie spodziewać.

    Ułatwienia składni dla tablic

    Ułatwienia składni dla tablic to wykorzystanie generatorów, pozwalające w wygodny sposób wykonywać skomplikowane inicjalizacje tablic. Na przykład:

    function range(begin, end) {
      for (let i = begin; i < end; ++i) {
        yield i;
      }
    }
    

    range() jest generatorem, który zwraca wszystkie wartości między begin i end. Mając taką funkcję gotową, możemy jej użyć na przykład tak:

    var ten_squares = [i * i for (i in range(0, 10))];
    

    Nowa tablica, ten_squares, zawiera kwadraty liczb w zakresie od 0..9.

    Możesz użyć dowolnych wyrażeń do inicjalizacji tablic. Jeśli chcesz stworzyć tablicę zawierającą parzyste liczby od 0 do 20, możesz użyć takiego wyrażenia:

    var evens = [i for (i in range(0, 21)) if (i % 2 == 0)];
    

    Przed JavaScriptem 1.7, aby to osiągnąć musiałbyś napisać coś w tym stylu:

    var evens = [];
    for (var i=0; i <= 20; i++) {
      if (i % 2 == 0)
        evens.push(i);
    }
    

    Nowa metoda jest nie tylko znacznie krótsza, ale także czytelniejsza, kiedy już przyzwyczaisz się do nowej koncepcji.

    Reguły zasięgu

    Array comprehensions są zawarte w oznaczonym bloku, wewnątrz kwadratowych nawiasów, tak samo jak deklaracje let.

    Więcej szczegółów.

    Zasięg blokowy z let

    Istnieje kilka metod, w których możesz wykorzystać let do zarządzania zasięgiem blokowym danych i funkcji:

    • Wyrażenie let pozwala na wiązanie wartości ze zmiennymi, stałymi i funkcjami wewnątrz zasięgu bloku bez wpływu na wartości zmiennych o tej samej nazwie znajdujących się poza blokiem.
    • Wyrażenie let pozwala stworzyć zmienne o zasięgu ograniczonym tylko do jednego wyrażenia.
    • Definicja let definiuje zmienne, stałe i funkcje których zasięg jest ograniczony do bloku w którym zostały zdefiniowane. Taka składnia bardzo przypomina składnię używaną dla var.
    • Możesz także użyć let do stworzenia zmiennych, które istnieją tylko wewnątrz kontekstu pętli for.

    Wyrażenie let

    Wyrażenie let wprowadza lokalny zasięg dla zmiennych, stałych i funkcji. Wiąże on zero lub więcej zmiennych do leksykalnego zasięgu jednego bloku kodu; w przeciwnym wypadku działa tak samo jak wyrażenie block. Zauważ, że zasięg zmiennej wewnątrz wyrażenia let używając var jest ciągle taki sam gdy byłby on zadeklarowany na zewnątrz wyrażenia let; takie zmienne wciąż posiadają zasięg funkcji.

    Na przykład:

    var x = 5;
    var y = 0;
    
    let (x = x+10, y = 12) {
      document.write(x+y + "\n");
    }
    
    document.write(x+y + "\n");

    Wynik programu:

    27
    5
    


    Reguły dla tego bloku kodu są takie same jak dla każdego innego bloku kodu w JavaScripcie. Może on posiadać swoje własne, lokalne zmienne określone przy użyciu deklaracji let.

    Uwaga: Podczas używania składni let, nawiasy występujące po let są konieczne. Pominięcie ich będzie skutkowało błędem składni.
    Reguły zasięgu

    Zmienne określone przy użyciu let mają zasięg bloku let, oraz każdego bloku zawartego wewnątrz niego, chyba, że te bloki zadeklarują własne zmienne o tych samych nazwach.

    Wyrażenia let

    Możesz używać let do tworzenia zmiennych, które mają być w zasięgu tylko jednego wyrażenia:

    var x = 5;
    var y = 0;
    document.write( let(x = x + 10, y = 12) x+y + "<br>\n");
    document.write(x+y + "<br>\n");
    

    Wynikiem będzie:

    27
    5
    

    W tym przypadku, powiązanie wartości x oraz y do x+10 oraz 12 ma tylko zasięg pojedyńczego wyrażenia x+y.

    Reguły zasięgu

    Mając wyrażenie let takie jak:

    let (decls) expr</font>
    

    Wokół expr</font> zostaje stworzony tzw. blok bezpośredni (eng. implicit block).

    Definicje let

    Słowo kluczowe let może także zostać użyte do definiowania zmiennych, stałych i funkcji wewnątrz bloku.

    Uwaga: Jeśli posiadasz ciekawsze przykłady użycia definicji let dodaj te proszę poniżej.
    if (x > y)
    {
       let gamma = 12.7 + y;
       i = gamma * x;
    }
    

    let statements, expressions and definitions sometimes make the code cleaner when inner functions are used.

    var list = document.getElementById("list");
    for (var i = 1; i <= 5; i++)
    {
      var item = document.createElement("LI");
      item.appendChild(document.createTextNode("Item " + i));
      let j = i;
      item.onclick = function (ev) {
        alert("Item " + j + " is clicked.");
      };
      list.appendChild(item);
    }
    

    The example above works as intended because the five instances of the (anonymous) inner function refer to five different instances of variable j. Note that it does not work as intended if you replace let by var or if you remove the variable j and simply use the variable i in the inner function.

    Reguły zasięgu

    Variables declared by let have as their scope the block in which they are defined, as well as in any sub-blocks in which they aren't redefined. In this way, let works very much like var. The main difference is that the scope of a var variable is the entire enclosing function:

      function varTest() {
        var x = 31;
        if (true) {
          var x = 71;  // same variable!
          alert(x);  // 71
        }
        alert(x);  // 71
      }
    
      function letTest() {
        let x = 31;
        if (true) {
          let x = 71;  // different variable
          alert(x);  // 71
        }
        alert(x);  // 31
      }
    

    The expression to the right of the = is inside the block. This is different from how let-expressions and let-statements are scoped:

      function letTests() {
        let x = 10;
    
        // let-statement
        let (x = x + 20) {
          alert(x);  // 30
        }
    
        // let-expression
        alert(let (x = x + 20) x);  // 30
    
        // let-definition
        {
          let x = x + 20;  // x here evaluates to undefined
          alert(x);  // undefined + 20 ==> NaN
        }
      }
    

    W programach i klasach let nie tworzy własności w obiektach globalnych ani w obiektach klas, tak jak to czyni var; w zamian, tworzy własność w bezpośrednim bloku, stworzonym do obliczenia wartości wyrażenia w tych kontekstach. W sumie oznacza to, że let nie nadpisze zmiennych zdefiniowanych wcześniej przez var. Na przykład:

    ** Nie działa w FF 2.0 b1. Zwraca "42", a nie "global".
    var x = 'global';
    let x = 42;
    document.write(this.x + "<BR>\n")
    

    Wyjście, wyświetlone przez ten kod pokaże napis "global", a nie " 42".

    Bezpośredni blok oznacza blok, który nie jest określony nawiasami; jest on stworzony bezpośrednio przez silnik JavaScript.

    W funkcjach, let użyte wewnątrz eval() nie tworzy własności w obiekcie zmiennej (obiekt aktywujący, lub najbliższe wiązanie) jak robi to var; w zamian, tworzy własności w bezpośrdnim bloku tworzonym do obliczenia wyrażenia w programie. Jest to konsekwencja tego, że eval() operuje na programach oraz poprzedniej reguły.

    Innymi słowy, kiedy używasz eval() do wywołania kodu, ten kod jest traktowany jako osobny program, który posiada własny bezpośredni blok wokół swojego kodu.

    Zmienne zasięgu let w pętlach for

    Możesz używać słowa kluczowego let, aby wiązać zmienne lokalnie w zasięgu pętli for, tak samo jak możesz robić to z var.

    ** Add obj **
       var i=0;
       for ( let i=i ; i < 10 ; i++ )
         document.write(i + "<br>\n");
    
       for ( let [name,value] in obj )
         document.write("Nazwa: " + name + ", Wartość: " + value + "<br>\n");
    
    Reguły zasięgu
    for (let expr1; <var>expr2; <var>expr3) statement</font>
    

    W tym przykładzie, expr2, expr3, oraz <var>statement są zamknięte w bezpośrednim bloku zawierającym lokalne zmienne zadeklarowane przez let expr1. Jest to zaprezentowane w pierwszej pętli powyżej.

    for (expr1 in expr2) statement
    

    W tym przypadku, istnieje bezpośredni blok zawierający statement. Jest to zaprezentowane w drugiej pętli powyżej.

    Rozpakowywanie struktur

    Rozpakowywanie struktur daje możliwość wydobycia danych z tablic lub obiektów, używając składni, która mapuje je na zmienne tablic i obiektów jako wyniku.

    The object and array literal expressions provide an easy way to create ad-hoc packages of data. Once you've created these packages of data, you can use them any way you want to. You can even return them from functions.

    One particularly useful thing you can do with destructuring assignment is to read an entire structure in a single statement, although there are a number of interesting things you can do with them, as shown in the section full of examples that follows.

    Ta funkcjonalność jest podobna do własności takich języków jak Perl czy Python.

    Przykłady

    Destructuring assignment is best explained through the use of examples, so here are a few for you to read over and learn from.

    Unikanie zmiennych tymczasowych

    You can use destructuring assignment, for example, to swap values:

    var a = 1;
    var b = 3;
    
    [a, b] = [b, a];
    

    After executing this code, b is 1 and a is 3. Without destructuring assignment, swapping two values requires a temporary variable (or, in some low-level languages, the XOR-swap trick).

    Similarly, it can be used to rotate three or more variables:

    var a = 'o';
    var b = "<span style='color:green;'>o</span>";
    var c = 'o';
    var d = 'o';
    var e = 'o';
    var f = "<span style='color:blue;'>o</span>";
    var g = 'o';
    var h = 'o';
    
    for (lp=0;lp<40;lp++)
    	{[a, b, c, d, e, f, g, h] = [b, c, d, e, f, g, h, a];
    	 document.write(a+''+b+''+c+''+d+''+e+''+f+''+g+''+h+''+"<br />");}
    

    After executing this code, a visual colorful display of the variable rotation will be displayed.

    Returning to our Fibonacci generator example from above, we can eliminate the temporary "t" variable by computing the new values of "i" and "j" in a single group-assignment statement:

    function fib() {
      var i = 0, j = 1;
      while (true) {
        yield i;
        [i, j] = [j, i + j];
      }
    }
    
    var g = fib();
    for (let i = 0; i < 10; i++)
      print(g.next());
    
    Zwracanie wielu wartości

    Dzięki rozpakowywaniu struktur, funkcje mogą zwracać wiele wartości. While it's always been possible to return an array from a function, this provides an added degree of flexibility.

    function f() {
      return [1, 2];
    }
    

    As you can see, returning results is done using an array-like notation, with all the values to return enclosed in brackets. You can return any number of results in this way. In this example, f() returns the values [1, 2] as its output.

    var a, b;
    [a, b] = f();
    document.write ("A is " + a + " B is " + b + "<br>\n");
    

    Po wykonaniu tego kodu, a ma wartość 1, a b ma wartość 2. You can also retrieve the return values as an array:

    var a = f();
    document.write ("A is " + a);
    

    In this case, a is an array containing the values 1 and 2.

    Iterowanie przez obiekty

    Możesz też użyć rozpakowywania struktur do pobierania danych z obiektu:

    let obj = { width: 3, length: 1.5, color: "orange" };
    for (let [name, value] in Iterator(obj)) {
      document.write ("Name: " + name + ", Value: " + value + "<br>\n");
    }
    

    This loops over all the key/value pairs in the object obj and displays their names and values. In this case, the output looks like the following:

    Name: width, Value: 3
    Name: length, Value: 1.5
    Name: color, Value: orange
    

    The Iterator() around obj is not necessary in JavaScript 1.7; however, it will be needed for JavaScript 1.8. This is to allow destructuring assignment with arrays (see błąd 366941).


    Iterowanie przez wartości w macierzy obiektów

    Możesz też iterować przez wartości w macierzy obiektów wyciągając wartości z każdego obiektu:

    var people = [
      {
        name: "Mike Smith",
        family: {
          mother: "Jane Smith",
          father: "Harry Smith",
          sister: "Samantha Smith"
        },
        age: 35
      },
      {
        name: "Tom Jones",
        family: {
          mother: "Norah Jones",
          father: "Richard Jones",
          brother: "Howard Jones"
        },
        age: 25
      }
    ];
    
    for each (let {name: n, family: { father: f } } in people) {
      document.write ("Name: " + n + ", Father: " + f + "<br>\n");
    }
    

    This pulls the name field into n and the family.father field into f, then prints them. This is done for each object in the people array. The output looks like this:

    Name: Mike Smith, Father: Harry Smith
    Name: Tom Jones, Father: Richard Jones
    
    Pomijanie niektórych wartości zwracanych

    You can also ignore return values that you're not interested in:

    function f() {
      return [1, 2, 3];
    }
    
    var [a, , b] = f();
    document.write ("A is " + a + " B is " + b + "<br>\n");
    

    After running this code, a is 1 and b is 3. The value 2 is ignored. You can ignore any (or all) returned values this way. For example:

    [,,,] = f();
    
    Wyciąganie wartości z wyrażeń regularnych

    When the regular expression exec() method finds a match, it returns an array containing first the entire matched portion of the string and then the portions of the string that matched each parenthesized group in the regular expression. Destructuring assignment allows you to pull the parts out of this array easily, ignoring the full match if it is not needed.

    // Simple regular expression to match http / https / ftp-style URLs.
    var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
    if (!parsedURL)
      return null;
    var [, protocol, fullhost, fullpath] = parsedURL;
    

    Autorzy i etykiety dokumentu

    Contributors to this page: Prefiks, Bedi, teoli, Filemon, gandalf, Mgjbot, Ptak82
    Ostatnia aktualizacja: teoli,