Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 88 additions & 88 deletions 1-js/05-data-types/06-iterable/article.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,58 @@

# 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 = {
from: 1,
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 = {
from: 1,
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 {
Expand All @@ -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 = {
Expand All @@ -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, e, 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);

*!*
Expand All @@ -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 = {
Expand All @@ -211,68 +211,68 @@ 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);

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]); // 𝒳
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);
}

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) {
Expand All @@ -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.