diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md index e2c0d4f9..65148667 100644 --- a/1-js/05-data-types/06-iterable/article.md +++ b/1-js/05-data-types/06-iterable/article.md @@ -1,20 +1,20 @@ -# Iterables +# Itererbare objekter -*Iterable* objects are a generalization of arrays. That's a concept that allows us to make any object useable in a `for..of` loop. +*Iterable* objekter er en generalisering af arrays. Det er et koncept, der tillader os at gøre ethvert objekt brugbart i en `for..of`-løkke. -Of course, Arrays are iterable. But there are many other built-in objects, that are iterable as well. For instance, strings are also iterable. +Selvfølgelig er arrays itererbare. Men der findes mange andre indbyggede objekter, som også er iterable. For eksempel er strenge også iterable. -If an object isn't technically an array, but represents a collection (list, set) of something, then `for..of` is a great syntax to loop over it, so let's see how to make it work. +Hvis et objekt teknisk set ikke er et array, men repræsenterer en samling (liste, sæt) af noget, så er `for..of` en fremragende syntaks til at iterere over det, så lad os se, hvordan man får det til at fungere. ## Symbol.iterator -We can easily grasp the concept of iterables by making one of our own. +Vi kan nemt forstå konceptet med itererbare objekter ved at lave en af vores egne. -For instance, we have an object that is not an array, but looks suitable for `for..of`. +For eksempel har vi et objekt, der ikke er et array, men som ser ud til at være egnet til `for..of`. -Like a `range` object that represents an interval of numbers: +Som et `range`-objekt, der repræsenterer et interval af tal: ```js let range = { @@ -22,18 +22,18 @@ let range = { to: 5 }; -// We want the for..of to work: +// Vi vil have for..of til at virke: // for(let num of range) ... num=1,2,3,4,5 ``` -To make the `range` object iterable (and thus let `for..of` work) we need to add a method to the object named `Symbol.iterator` (a special built-in symbol just for that). +For at gøre `range`-objektet itererbart (og dermed lade `for..of` fungere) skal vi tilføje en metode til objektet med navnet `Symbol.iterator` (et specielt indbygget symbol til netop det formål). -1. When `for..of` starts, it calls that method once (or errors if not found). The method must return an *iterator* -- an object with the method `next`. -2. Onward, `for..of` works *only with that returned object*. -3. When `for..of` wants the next value, it calls `next()` on that object. -4. The result of `next()` must have the form `{done: Boolean, value: any}`, where `done=true` means that the loop is finished, otherwise `value` is the next value. +1. Når `for..of` starter kaldes metoden en gang (eller fejler, hvis den ikke findes). Metoden skal returnere en *iterator* -- et objekt med metoden `next`. +2. Herefter arbejder `for..of` *kun med det returnerede objekt*. +3. Når `for..of` ønsker den næste værdi, kalder den `next()` på det objekt. +4. Resultatet af `next()` skal have formen `{done: Boolean, value: any}`, hvor `done=true` betyder, at løkken er færdig, ellers er `value` den næste værdi. -Here's the full implementation for `range` with remarks: +Her er den fulde implementering for `range` med bemærkninger: ```js run let range = { @@ -41,18 +41,18 @@ let range = { to: 5 }; -// 1. call to for..of initially calls this +// 1. kald til for..of kalder oprindeligt dette range[Symbol.iterator] = function() { - // ...it returns the iterator object: - // 2. Onward, for..of works only with the iterator object below, asking it for next values + // ...det returnerer iterator-objektet: + // 2. Herefter arbejder for..of kun med iterator-objektet nedenfor, som spørger efter næste værdier return { current: this.from, last: this.to, - // 3. next() is called on each iteration by the for..of loop + // 3. next() kaldes på hver iteration af for..of-løkken next() { - // 4. it should return the value as an object {done:.., value :...} + // 4. det bør returnere værdien som et objekt {done:.., value :...} if (this.current <= this.last) { return { done: false, value: this.current++ }; } else { @@ -62,22 +62,22 @@ range[Symbol.iterator] = function() { }; }; -// now it works! +// nu virker det! for (let num of range) { alert(num); // 1, then 2, 3, 4, 5 } ``` -Please note the core feature of iterables: separation of concerns. +Bemærk den grundlæggende egenskab ved iterables: adskillelse af bekymringer. -- The `range` itself does not have the `next()` method. -- Instead, another object, a so-called "iterator" is created by the call to `range[Symbol.iterator]()`, and its `next()` generates values for the iteration. +- Selve `range` har ikke `next()`-metoden. +- I stedet oprettes et andet objekt, en såkaldt "iterator", ved kaldet til `range[Symbol.iterator]()`, og dens `next()` genererer værdier til iterationen. -So, the iterator object is separate from the object it iterates over. +Således er iterator-objektet adskilt fra det objekt, det itererer over. -Technically, we may merge them and use `range` itself as the iterator to make the code simpler. +Teknisk set kan vi slå dem sammen og bruge `range` selv som iteratoren for at gøre koden enklere. -Like this: +Som dette: ```js run let range = { @@ -103,51 +103,51 @@ for (let num of range) { } ``` -Now `range[Symbol.iterator]()` returns the `range` object itself: it has the necessary `next()` method and remembers the current iteration progress in `this.current`. Shorter? Yes. And sometimes that's fine too. +Nu returnerer `range[Symbol.iterator]()` `range`-objektet selv: det har den nødvendige `next()`-metode og husker den aktuelle iterationsstatus i `this.current`. Kortere? Ja. Og nogle gange er det også fint. -The downside is that now it's impossible to have two `for..of` loops running over the object simultaneously: they'll share the iteration state, because there's only one iterator -- the object itself. But two parallel for-ofs is a rare thing, even in async scenarios. +Ulempen er, at det nu er umuligt at have to `for..of`-løkker, der kører over objektet samtidig: de vil dele iterationsstatus, fordi der kun er én iterator -- objektet selv. Men to parallelle for-ofs er en sjælden ting, selv i asynkrone scenarier. -```smart header="Infinite iterators" -Infinite iterators are also possible. For instance, the `range` becomes infinite for `range.to = Infinity`. Or we can make an iterable object that generates an infinite sequence of pseudorandom numbers. Also can be useful. +```smart header="Uendelige iteratorer" +Uendelige iteratorer er også mulige. For eksempel bliver `range` uendelig for `range.to = Infinity`. Eller vi kan lave et itererbart objekt, der genererer en uendelig sekvens af pseudotilfældige tal. Det kan også være nyttigt. -There are no limitations on `next`, it can return more and more values, that's normal. +Der er ingen begrænsninger på `next`, den kan returnere flere og flere værdier, det er normalt. -Of course, the `for..of` loop over such an iterable would be endless. But we can always stop it using `break`. +Selvfølgelig ville `for..of`-løkken over sådan et iterable være uendelig. Men vi kan altid stoppe den ved hjælp af `break`. ``` -## String is iterable +## Strenge er itererbare -Arrays and strings are most widely used built-in iterables. +Arrays og strenge er de mest udbredte indbyggede iteraterbare objekter. -For a string, `for..of` loops over its characters: +For en streng, `for..of` løkker over dens tegn: ```js run for (let char of "test") { - // triggers 4 times: once for each character - alert( char ); // t, then e, then s, then t + // aktiveres 4 gange: en gang for hvert tegn + alert( char ); // t, så e, så s, så t } ``` -And it works correctly with surrogate pairs! +Og det virker korrekt med specielle tegn! ```js run let str = '𝒳😂'; for (let char of str) { - alert( char ); // 𝒳, and then 😂 + alert( char ); // 𝒳, og så 😂 } ``` -## Calling an iterator explicitly +## Kald en iterator eksplicit -For deeper understanding, let's see how to use an iterator explicitly. +For en dybere forståelse, lad os se, hvordan man bruger en iterator eksplicit. -We'll iterate over a string in exactly the same way as `for..of`, but with direct calls. This code creates a string iterator and gets values from it "manually": +Vi vil iterere over en streng på præcis samme måde som `for..of`, men med direkte kald. Denne kode opretter en strengiterator og får værdier fra den "manuelt": ```js run let str = "Hello"; -// does the same as +// gør det samme som // for (let char of str) alert(char); *!* @@ -157,49 +157,49 @@ let iterator = str[Symbol.iterator](); while (true) { let result = iterator.next(); if (result.done) break; - alert(result.value); // outputs characters one by one + alert(result.value); // udskriver tegn ét ad gangen } ``` -That is rarely needed, but gives us more control over the process than `for..of`. For instance, we can split the iteration process: iterate a bit, then stop, do something else, and then resume later. +Det er sjældent nødvendigt, men giver os mere kontrol over processen end `for..of`. For eksempel kan vi opdele iterationsprocessen: iterere lidt, så stoppe, gøre noget andet, og derefter genoptage senere. -## Iterables and array-likes [#array-like] +## Itererbare objekter og array-likes [#array-like] -Two official terms look similar, but are very different. Please make sure you understand them well to avoid the confusion. +To officielle termer ser ens ud men betyder forskellige ting. De kan forstås på følgende måde, så du ikke bliver forvirret. -- *Iterables* are objects that implement the `Symbol.iterator` method, as described above. -- *Array-likes* are objects that have indexes and `length`, so they look like arrays. +- *Iterables* (iteraterbare objekter) er objekter, der implementerer `Symbol.iterator`-metoden, som beskrevet ovenfor. +- *Array-likes* er objekter, der har indeks og `length`, så de ligner arrays. -When we use JavaScript for practical tasks in a browser or any other environment, we may meet objects that are iterables or array-likes, or both. +Når vi bruger JavaScript til praktiske opgaver i en browser eller et andet miljø, kan vi støde på objekter, der er itererbare eller array-likes, eller begge dele. -For instance, strings are both iterable (`for..of` works on them) and array-like (they have numeric indexes and `length`). +For eksempel er strenge både itererbare (`for..of` virker på dem) og array-likes (de har numeriske indekser og `length`). -But an iterable may not be array-like. And vice versa an array-like may not be iterable. +Men en itererbar behøver ikke at være array-like. Og omvendt kan en array-like ikke være itererbar. -For example, the `range` in the example above is iterable, but not array-like, because it does not have indexed properties and `length`. +For eksempel var `range` fra eksemplet ovenfor itererbar men ikke array-lignende, fordi det ikke har indekserede egenskaber og `length`. -And here's the object that is array-like, but not iterable: +Og her er objektet, der er array-lignende, men ikke itererbart: ```js run -let arrayLike = { // has indexes and length => array-like +let arrayLike = { // har indeks og length => array-like 0: "Hello", 1: "World", length: 2 }; *!* -// Error (no Symbol.iterator) +// Fejl (ingen Symbol.iterator) for (let item of arrayLike) {} */!* ``` -Both iterables and array-likes are usually *not arrays*, they don't have `push`, `pop` etc. That's rather inconvenient if we have such an object and want to work with it as with an array. E.g. we would like to work with `range` using array methods. How to achieve that? +Både itererbare objekter og array-likes er som regel *ikke arrays*, de har ikke `push`, `pop` osv. Det er ret upraktisk, hvis vi har et sådant objekt og ønsker at arbejde med det som med et array. F.eks. vil vi gerne arbejde med `range` ved hjælp af array-metoder. Hvordan opnår vi det? ## Array.from -There's a universal method [Array.from](mdn:js/Array/from) that takes an iterable or array-like value and makes a "real" `Array` from it. Then we can call array methods on it. +Der findes en universel metode [Array.from](mdn:js/Array/from), der tager en itererbar eller array-lignende værdi og laver et "rigtigt" `Array` ud af den. Så kan vi kalde array-metoder på det. -For instance: +For eksempel: ```js run let arrayLike = { @@ -211,30 +211,30 @@ let arrayLike = { *!* let arr = Array.from(arrayLike); // (*) */!* -alert(arr.pop()); // World (method works) +alert(arr.pop()); // World (metoden virker) ``` -`Array.from` at the line `(*)` takes the object, examines it for being an iterable or array-like, then makes a new array and copies all items to it. +`Array.from` på linjen `(*)` tager objektet, undersøger det for at være en itererbar eller array-lignende, laver derefter et nyt array og kopierer alle elementer til det. -The same happens for an iterable: +Det samme sker for en itererbar: ```js run -// assuming that range is taken from the example above +// antager at range er taget fra eksemplet ovenfor let arr = Array.from(range); -alert(arr); // 1,2,3,4,5 (array toString conversion works) +alert(arr); // 1,2,3,4,5 (array toString konvertering virker) ``` -The full syntax for `Array.from` also allows us to provide an optional "mapping" function: +Den fulde syntaks for `Array.from` tillader os også at angive en valgfri "mapping"-funktion: ```js Array.from(obj[, mapFn, thisArg]) ``` -The optional second argument `mapFn` can be a function that will be applied to each element before adding it to the array, and `thisArg` allows us to set `this` for it. +The frivillige andet argument `mapFn` kan være en funktion, der anvendes på hvert element, før det tilføjes til arrayet, og `thisArg` tillader os at sætte `this` for det. -For instance: +For eksempel: ```js run -// assuming that range is taken from the example above +// antager at range er taget fra eksemplet ovenfor // square each number let arr = Array.from(range, num => num * num); @@ -242,12 +242,12 @@ let arr = Array.from(range, num => num * num); alert(arr); // 1,4,9,16,25 ``` -Here we use `Array.from` to turn a string into an array of characters: +Her bruger vi `Array.from` til at omdanne en streng til et array af tegn: ```js run let str = '𝒳😂'; -// splits str into array of characters +// splitter str til et array af tegn let chars = Array.from(str); alert(chars[0]); // 𝒳 @@ -255,14 +255,14 @@ alert(chars[1]); // 😂 alert(chars.length); // 2 ``` -Unlike `str.split`, it relies on the iterable nature of the string and so, just like `for..of`, correctly works with surrogate pairs. +I modsætning til `str.split` er den afhængig af strengens itererbare natur og fungerer derfor, ligesom `for..of`, korrekt med surrogate par. -Technically here it does the same as: +Teknisk set gør den her det samme som: ```js run let str = '𝒳😂'; -let chars = []; // Array.from internally does the same loop +let chars = []; // Array.from gør internt det samme loop for (let char of str) { chars.push(char); } @@ -270,9 +270,9 @@ for (let char of str) { alert(chars); ``` -...But it is shorter. +...men det er kortere. -We can even build surrogate-aware `slice` on it: +Vi kan endda bygge en `slice` der er opmærksom på specielle tegn: ```js run function slice(str, start, end) { @@ -283,25 +283,25 @@ let str = '𝒳😂𩷶'; alert( slice(str, 1, 3) ); // 😂𩷶 -// the native method does not support surrogate pairs -alert( str.slice(1, 3) ); // garbage (two pieces from different surrogate pairs) +// den indbyggede metode understøtter ikke specielle tegn (kaldet surrogate par) +alert( str.slice(1, 3) ); // virker ikke (giver to stykker fra forskellige specialtegn) ``` -## Summary +## Opsummering -Objects that can be used in `for..of` are called *iterable*. +Objekter, der kan bruges i `for..of`, kaldes *itererbare*. -- Technically, iterables must implement the method named `Symbol.iterator`. - - The result of `obj[Symbol.iterator]()` is called an *iterator*. It handles further iteration process. - - An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the end of the iteration process, otherwise the `value` is the next value. -- The `Symbol.iterator` method is called automatically by `for..of`, but we also can do it directly. -- Built-in iterables like strings or arrays, also implement `Symbol.iterator`. -- String iterator knows about surrogate pairs. +- Teknisk set skal itererbare implementere metoden med navnet `Symbol.iterator`. + - Resultatet af `obj[Symbol.iterator]()` kaldes en *iterator*. Den håndterer den videre iterationsproces. + - En iterator skal have metoden med navnet `next()`, som returnerer et objekt `{done: Boolean, value: any}`, hvor `done:true` angiver slutningen af iterationsprocessen, ellers er `value` den næste værdi. +- Metoden `Symbol.iterator` kaldes automatisk af `for..of`, men vi kan også gøre det direkte. +- Indbyggede itererbare som strenge eller arrays implementerer også `Symbol.iterator`. +- String-iteratoren kender til surrogate par. -Objects that have indexed properties and `length` are called *array-like*. Such objects may also have other properties and methods, but lack the built-in methods of arrays. +Objekter, der har indekserede egenskaber og `length`, kaldes *array-lignende*. Sådanne objekter kan også have andre egenskaber og metoder, men mangler de indbyggede metoder fra arrays. -If we look inside the specification -- we'll see that most built-in methods assume that they work with iterables or array-likes instead of "real" arrays, because that's more abstract. +Hvis vi kigger inde i specifikationen -- vil vi se, at de fleste indbyggede metoder antager, at de arbejder med itererbare eller array-lignende i stedet for "rigtige" arrays, fordi det er mere abstrakt. -`Array.from(obj[, mapFn, thisArg])` makes a real `Array` from an iterable or array-like `obj`, and we can then use array methods on it. The optional arguments `mapFn` and `thisArg` allow us to apply a function to each item. +`Array.from(obj[, mapFn, thisArg])` laver et rigtigt `Array` fra et itererbart eller array-lignende `obj`, og vi kan derefter bruge array-metoder på det. De valgfrie argumenter `mapFn` og `thisArg` tillader os at anvende en funktion på hvert element.