diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md index f3c9cf0e5..234388dfb 100644 --- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md +++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md @@ -1,31 +1,31 @@ -The method can take all enumerable keys using `Object.keys` and output their list. +Metoden kan tage alle enumerable (tælbare) nøgler ved hjælp af `Object.keys` og outputte deres liste. -To make `toString` non-enumerable, let's define it using a property descriptor. The syntax of `Object.create` allows us to provide an object with property descriptors as the second argument. +For at gøre `toString` non-enumerable, lad os definere den ved hjælp af en egenskabsbeskrivelse. Syntaksen for `Object.create` giver os mulighed for at give et objekt med egenskabsbeskrivelser som anden argument. ```js run *!* let dictionary = Object.create(null, { - toString: { // define toString property - value() { // the value is a function + toString: { // definer egenskaben toString + value() { // value er en funktion return Object.keys(this).join(); } } }); */!* -dictionary.apple = "Apple"; +dictionary.apple = "Æble"; dictionary.__proto__ = "test"; -// apple and __proto__ is in the loop +// Kun apple og __proto__ er i loopet for(let key in dictionary) { - alert(key); // "apple", then "__proto__" + alert(key); // "apple" og "__proto__" } -// comma-separated list of properties by toString +// kommasepareret liste af egenskaber fra toString alert(dictionary); // "apple,__proto__" ``` -When we create a property using a descriptor, its flags are `false` by default. So in the code above, `dictionary.toString` is non-enumerable. +Når vi opretter en egenskab ved hjælp af en egenskabsbeskrivelser, er dens flag som standard sat til `false`. Så i koden ovenfor er `dictionary.toString` non-enumerable. -See the chapter [](info:property-descriptors) for review. +Se kapitlet [](info:property-descriptors) for en gennemgang. diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md index 0d831f2cc..82521674e 100644 --- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md +++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md @@ -2,30 +2,30 @@ importance: 5 --- -# Add toString to the dictionary +# Tilføj toString til ordbogen -There's an object `dictionary`, created as `Object.create(null)`, to store any `key/value` pairs. +Der er et objekt `dictionary`, oprettet som `Object.create(null)`, til at gemme enhver `key/value` par. -Add method `dictionary.toString()` into it, that should return a comma-delimited list of keys. Your `toString` should not show up in `for..in` over the object. +Tilføj metoden `dictionary.toString()` til det, som skal returnere en komma-separeret liste af nøgler. Din `toString` bør ikke vises i `for..in` over objektet. -Here's how it should work: +Den bør virke sådan her: ```js let dictionary = Object.create(null); *!* -// your code to add dictionary.toString method +// din kode til at tilføje dictionary.toString metoden */!* -// add some data -dictionary.apple = "Apple"; +// tilføj nogle data +dictionary.apple = "æble"; dictionary.__proto__ = "test"; // __proto__ is a regular property key here -// only apple and __proto__ are in the loop +// Kun apple og __proto__ er i loopet for(let key in dictionary) { - alert(key); // "apple", then "__proto__" + alert(key); // "apple" og "__proto__" } -// your toString in action +// din toString i aktion alert(dictionary); // "apple,__proto__" ``` diff --git a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md index 90d3118bf..995c79f2c 100644 --- a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md +++ b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md @@ -1,7 +1,7 @@ -The first call has `this == rabbit`, the other ones have `this` equal to `Rabbit.prototype`, because it's actually the object before the dot. +Det første kald har `this == rabbit`, de andre har `this` lig med `Rabbit.prototype`, fordi det faktisk er objektet før punktummet. -So only the first call shows `Rabbit`, other ones show `undefined`: +Så kun det første kald viser `Rabbit`, andre viser `undefined`: ```js run function Rabbit(name) { @@ -11,9 +11,9 @@ Rabbit.prototype.sayHi = function() { alert( this.name ); } -let rabbit = new Rabbit("Rabbit"); +let rabbit = new Rabbit("Kanin"); -rabbit.sayHi(); // Rabbit +rabbit.sayHi(); // Kanin Rabbit.prototype.sayHi(); // undefined Object.getPrototypeOf(rabbit).sayHi(); // undefined rabbit.__proto__.sayHi(); // undefined diff --git a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md index 09bb7f1ed..672883d46 100644 --- a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md +++ b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# The difference between calls +# Forskellen mellem kald -Let's create a new `rabbit` object: +Lad os oprette et nyt `rabbit` objekt: ```js function Rabbit(name) { @@ -14,10 +14,10 @@ Rabbit.prototype.sayHi = function() { alert(this.name); }; -let rabbit = new Rabbit("Rabbit"); +let rabbit = new Rabbit("Kanin"); ``` -These calls do the same thing or not? +Gør disse kald det samme eller gør de ikke? ```js rabbit.sayHi(); diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md index 9c5f1eb3d..3b54e6a91 100644 --- a/1-js/08-prototypes/04-prototype-methods/article.md +++ b/1-js/08-prototypes/04-prototype-methods/article.md @@ -1,31 +1,31 @@ -# Prototype methods, objects without __proto__ +# Prototype metoder, objekter uden __proto__ -In the first chapter of this section, we mentioned that there are modern methods to setup a prototype. +I det første kapitel i denne sektion nævnte vi, at der er moderne metoder til at sætte en prototype. -Setting or reading the prototype with `obj.__proto__` is considered outdated and somewhat deprecated (moved to the so-called "Annex B" of the JavaScript standard, meant for browsers only). +At sætte eller læse en prototype med `obj.__proto__` er betragtet som forældet og noget deprecated (flyttet til såkaldte "Annex B" i JavaScript-standarden, kun tilgængelig i browser-motorer). -The modern methods to get/set a prototype are: +De moderne metoder til at få/sætte en prototype er: -- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj`. -- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto`. +- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returnerer `[[Prototype]]` af `obj`. +- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sætter `[[Prototype]]` af `obj` til `proto`. -The only usage of `__proto__`, that's not frowned upon, is as a property when creating a new object: `{ __proto__: ... }`. +Den eneste brug af `__proto__`, der ikke rynkes på panden af er, som en en egenskab når der oprettes et nyt objekt: `{ __proto__: ... }`. -Although, there's a special method for this too: +Selvom der egentlig er en speciel metode for dette også: -- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors. +- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- opretter et tomt objekt med given `proto` som `[[Prototype]]` og valgfrie beskrivelser af egenskaber. -For instance: +For eksempel for at oprette et objekt med `animal` som prototype, kan vi bruge: ```js run let animal = { eats: true }; -// create a new object with animal as a prototype +// opret et nyt objekt med animal som prototype *!* -let rabbit = Object.create(animal); // same as {__proto__: animal} +let rabbit = Object.create(animal); // samme som {__proto__: animal} */!* alert(rabbit.eats); // true @@ -35,13 +35,13 @@ alert(Object.getPrototypeOf(rabbit) === animal); // true */!* *!* -Object.setPrototypeOf(rabbit, {}); // change the prototype of rabbit to {} +Object.setPrototypeOf(rabbit, {}); // Ændring af rabbits prototype til {} */!* ``` -The `Object.create` method is a bit more powerful, as it has an optional second argument: property descriptors. +Metoden `Object.create` er lidt mere kraftfuld, da den giver mulighed for at tilføje egenskaber til det nye objekt. Det er en valgfri anden parameter: egenskabsbeskrivelser. -We can provide additional properties to the new object there, like this: +Vi kan tilføje yderligere egenskaber til det nye objekt der, som dette: ```js run let animal = { @@ -57,9 +57,9 @@ let rabbit = Object.create(animal, { alert(rabbit.jumps); // true ``` -The descriptors are in the same format as described in the chapter . +Muligheden for beskrivelser er det samme format som beskrevet i kapitlet . -We can use `Object.create` to perform an object cloning more powerful than copying properties in `for..in`: +Vi kan bruge `Object.create` til at udføre en kloning af et objekt der er mere effektiv end at kopiere de enkelte egenskaber i et `for..in` loop: ```js let clone = Object.create( @@ -67,125 +67,125 @@ let clone = Object.create( ); ``` -This call makes a truly exact copy of `obj`, including all properties: enumerable and non-enumerable, data properties and setters/getters -- everything, and with the right `[[Prototype]]`. +Dette kald laver en helt præcis kopi af `obj`, inklusiv alle egenskaber: både enumerable og ikke-enumerable, data egenskaber og setters/getters -- alt, og med den rigtige `[[Prototype]]`. -## Brief history +## Et lille blik på historien bag -There're so many ways to manage `[[Prototype]]`. How did that happen? Why? +Der er SÅ mange måder at håndtere `[[Prototype]]`. Hvordan kunne det dog komme dertil? -That's for historical reasons. +Det er ganske enkelt en række historiske årsdager. -The prototypal inheritance was in the language since its dawn, but the ways to manage it evolved over time. +Nedarvning ved prototype har været muligt siden sprogets start, men måderne at håndtere den har udviklet sig over tid. -- The `prototype` property of a constructor function has worked since very ancient times. It's the oldest way to create objects with a given prototype. -- Later, in the year 2012, `Object.create` appeared in the standard. It gave the ability to create objects with a given prototype, but did not provide the ability to get/set it. Some browsers implemented the non-standard `__proto__` accessor that allowed the user to get/set a prototype at any time, to give more flexibility to developers. -- Later, in the year 2015, `Object.setPrototypeOf` and `Object.getPrototypeOf` were added to the standard, to perform the same functionality as `__proto__`. As `__proto__` was de-facto implemented everywhere, it was kind-of deprecated and made its way to the Annex B of the standard, that is: optional for non-browser environments. -- Later, in the year 2022, it was officially allowed to use `__proto__` in object literals `{...}` (moved out of Annex B), but not as a getter/setter `obj.__proto__` (still in Annex B). +- Egenskaben `prototype` som led i en konstruktørfunktion har virket helt fra begyndelsen. Det er den ældste måde at oprette objekter med en given prototype. +- Senere, i 2012, blev `Object.create` vedtaget som standard. Den gav mulighed for at oprette objekter med en given prototype, men gav ikke mulighed for at bruge get/set på den. Nogle browsere implementerede den ikke-standard `__proto__` tilgang, som tillod brugeren at bruge get/set på en prototype uden for konstruktøren, for at give mere fleksibilitet til udviklere. +- Senere, i 2015, blev `Object.setPrototypeOf` og `Object.getPrototypeOf` tilføjet til standarden, for at udføre samme funktionalitet som `__proto__`. Da `__proto__` var de-facto implementeret overalt, blev det delvis deprecated og bragt til Annex B af standarden, altså valgfrit for ikke-browser miljøer. +- Senere, i 2022, blev det officielt tilladt at bruge `__proto__` i objekt-literaler `{...}` (flyttet ud af Annex B), men ikke som en getter/setter `obj.__proto__` (stadig i Annex B). -Why was `__proto__` replaced by the functions `getPrototypeOf/setPrototypeOf`? +Hvorfor var `__proto__` erstattet af funktionerne `getPrototypeOf/setPrototypeOf`? -Why was `__proto__` partially rehabilitated and its usage allowed in `{...}`, but not as a getter/setter? +Hvorfor var `__proto__` delvist genindført så det er tilladt i objekt-literaler `{...}`, men ikke som en getter/setter `obj.__proto__`? -That's an interesting question, requiring us to understand why `__proto__` is bad. +Det er et interessant spørgsmål, der kræver, at vi forstår hvorfor `__proto__` er dårlig. -And soon we'll get the answer. +Og snart vil vi få svaret. -```warn header="Don't change `[[Prototype]]` on existing objects if speed matters" -Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time and don't modify it anymore: `rabbit` inherits from `animal`, and that is not going to change. +```warn header="Lad være med at ændre `[[Prototype]]` på eksisterende objekter hvis hastighed er vigtig" +Teknisk set kan vi oprette can get/set på en `[[Prototype]]` når som helst. Men i praksis sker det næsten altid kun ved oprettelsen af objektet. Ofte sætter vi kun `[[Prototype]]` én gang ved oprettelsen af objektet og undlader efterfølgende at ændre den ikke igen: `rabbit` nedarver fra `animal`, og det ændres ikke. -And JavaScript engines are highly optimized for this. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation as it breaks internal optimizations for object property access operations. So avoid it unless you know what you're doing, or JavaScript speed totally doesn't matter for you. +JavaScript-motorer er højst optimerede til dette. Ændring af en prototype "on-the-fly" med `Object.setPrototypeOf` eller `obj.__proto__=` er en meget langsom operation, da den bryder interne optimeringer for objektegenskabstilgange. Undgå derfor at ændre prototypen, medmindre du ved hvad du gør, eller JavaScript-hastighed ikke spiller en rolle for dig. ``` -## "Very plain" objects [#very-plain] +## "Meget simple" objekter [#very-plain] -As we know, objects can be used as associative arrays to store key/value pairs. +Som vi ved kan objekter bruges som associative arrays til at gemme nøgle/værdi-par. -...But if we try to store *user-provided* keys in it (for instance, a user-entered dictionary), we can see an interesting glitch: all keys work fine except `"__proto__"`. +...Men hvis vi forsøger at gemme *brugerdefinerede* nøgler i det (for eksempel en brugerdefineret ordbog), kan vi se et interessant glitch: alle nøgler virker fint, bortset fra `"__proto__"`. -Check out the example: +Så for eksempel nedenfor: ```js run let obj = {}; -let key = prompt("What's the key?", "__proto__"); -obj[key] = "some value"; +let key = prompt("Hvad er nøglen?", "__proto__"); +obj[key] = "en værdi"; -alert(obj[key]); // [object Object], not "some value"! +alert(obj[key]); // [object Object], ikke "en værdi"! ``` -Here, if the user types in `__proto__`, the assignment in line 4 is ignored! +Her vil linje 4 ignoreres, hvis brugeren skriver `__proto__` i prompten! -That could surely be surprising for a non-developer, but pretty understandable for us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype. That's why assigning a string to `__proto__` is ignored. +Det er umiddelbart overraskende, men egentlig meget logisk, når vi husker på at egenskaben `__proto__` er lidt speciel: Den skal enten være et objekt eller `null`. En streng kan ikke blive en prototype. Derfor ignoreres tildeling af en streng til `__proto__`. -But we didn't *intend* to implement such behavior, right? We want to store key/value pairs, and the key named `"__proto__"` was not properly saved. So that's a bug! +Det var var jo ikke vores *plan* at den skulle opføre sig på den måde, vel? Vi vil gerne gemme nøgle/værdi-par, og nøglen kaldt `"__proto__"` blev ikke korrekt gemt. Så det er en fejl! -Here the consequences are not terrible. But in other cases we may be storing objects instead of strings in `obj`, and then the prototype will indeed be changed. As a result, the execution will go wrong in totally unexpected ways. +Her er konsekvenserne ikke så farlige. Men i andre tilfælde kan vi gemme objekter i stedet for strenge i `obj`, og så vil prototypen faktisk blive ændret. Som resultat vil eksekveringen gå galt på helt uventede måder. -What's worse -- usually developers do not think about such possibility at all. That makes such bugs hard to notice and even turn them into vulnerabilities, especially when JavaScript is used on server-side. +Det værre -- ofte tænker udviklere ikke over denne mulighed overhovedet. Det gør sådanne fejl svære at opdage og endda omvandles til sikkerhedsproblemer, især når JavaScript bruges på server-side. -Unexpected things also may happen when assigning to `obj.toString`, as it's a built-in object method. +Uventede ting kan også ske når vi tildeler til `obj.toString`, da det er en indbygget objektmetode. -How can we avoid this problem? +Hvordan kan vi undgå dette problem? -First, we can just switch to using `Map` for storage instead of plain objects, then everything's fine: +Først og fremmest kan vi skifte til at bruge `Map` for lagring i stedet for almindelige objekter, så alt er i orden: ```js run let map = new Map(); -let key = prompt("What's the key?", "__proto__"); -map.set(key, "some value"); +let key = prompt("Hvad er nøglen?", "__proto__"); +map.set(key, "en værdi"); -alert(map.get(key)); // "some value" (as intended) +alert(map.get(key)); // "en værdi" (som det var meningen) ``` -...But `Object` syntax is often more appealing, as it's more concise. +...Men `Object` syntaksen appelerer mere til de fleste - og den er kortere. -Fortunately, we *can* use objects, because language creators gave thought to that problem long ago. +Heldigvis *kan* vi bruge objekter fordi udviklerne af sproget har tænkt over dette problem for længe siden. -As we know, `__proto__` is not a property of an object, but an accessor property of `Object.prototype`: +Som vi ved er `__proto__` ikke i sig selv en egenskab af et objekt, men en accessor-egenskab af `Object.prototype`: ![](object-prototype-2.svg) -So, if `obj.__proto__` is read or set, the corresponding getter/setter is called from its prototype, and it gets/sets `[[Prototype]]`. +Så, hvis `obj.__proto__` læses eller sættes vil dens respektive getter/setter kaldes fra dens prototype, som så får eller sætter værdien af `[[Prototype]]`. -As it was said in the beginning of this tutorial section: `__proto__` is a way to access `[[Prototype]]`, it is not `[[Prototype]]` itself. +Som det blev sagt i begyndelsen: `__proto__` er en måde at tilgå `[[Prototype]]`, det er ikke selve objektet `[[Prototype]]`. -Now, if we intend to use an object as an associative array and be free of such problems, we can do it with a little trick: +Så, hvis vi planlægger at bruge et objekt som et associativt array og være fri for sådanne problemer, kan vi gøre det med et lille trick: ```js run *!* let obj = Object.create(null); -// or: obj = { __proto__: null } +// eller: obj = { __proto__: null } */!* -let key = prompt("What's the key?", "__proto__"); -obj[key] = "some value"; +let key = prompt("Hvad er nøglen?", "__proto__"); +obj[key] = "en værdi"; -alert(obj[key]); // "some value" +alert(obj[key]); // "en værdi" ``` -`Object.create(null)` creates an empty object without a prototype (`[[Prototype]]` is `null`): +`Object.create(null)` opretter et tomt objekt uden en prototype (`[[Prototype]]` er `null`): ![](object-prototype-null.svg) -So, there is no inherited getter/setter for `__proto__`. Now it is processed as a regular data property, so the example above works right. +På denne måde er der ingen arvede getter/setter for `__proto__`. Nu bliver det behandlet som en almindelig dataegenskab, så eksemplet ovenfor fungerer korrekt. -We can call such objects "very plain" or "pure dictionary" objects, because they are even simpler than the regular plain object `{...}`. +Vi kan kalde sådanne objekter "helt rene", fordi de er endnu mere simple end regulære rene objekter `{...}`. -A downside is that such objects lack any built-in object methods, e.g. `toString`: +En ulempe er, at sådanne objekter mangler alle indbyggede objektmetoder, f.eks. `toString`: ```js run *!* let obj = Object.create(null); */!* -alert(obj); // Error (no toString) +alert(obj); // Fejl (ingen toString) ``` -...But that's usually fine for associative arrays. +...men det er normalt ikke et problem for associative arrays. -Note that most object-related methods are `Object.something(...)`, like `Object.keys(obj)` -- they are not in the prototype, so they will keep working on such objects: +Bemærk, at de fleste objektrelaterede metoder er `Object.something(...)`, som `Object.keys(obj)` -- de er ikke i prototype, så de vil fortsat fungere på denne slags objekter: ```js run @@ -196,28 +196,28 @@ chineseDictionary.bye = "再见"; alert(Object.keys(chineseDictionary)); // hello,bye ``` -## Summary +## Opsummering -- To create an object with the given prototype, use: +- For at oprette et objekt med den givne prototype, brug: - - literal syntax: `{ __proto__: ... }`, allows to specify multiple properties - - or [Object.create(proto[, descriptors])](mdn:js/Object/create), allows to specify property descriptors. + - literal syntax: `{ __proto__: ... }`, tillader at specificere flere egenskaber + - eller [Object.create(proto[, descriptors])](mdn:js/Object/create), tillader at specificere egenskabsbeskrivelser. - The `Object.create` provides an easy way to shallow-copy an object with all descriptors: + `Object.create` giver en let måde at lave en flad kopi af et objekt med alle beskrivelser: ```js let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); ``` -- Modern methods to get/set the prototype are: +- Moderne metoder til at få eller sætte en prototype er: - - [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj` (same as `__proto__` getter). - - [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto` (same as `__proto__` setter). + - [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returnerer `[[Prototype]]` of `obj` (samme som `__proto__` getter). + - [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sætter `[[Prototype]]` of `obj` til `proto` (samme som `__proto__` setter). -- Getting/setting the prototype using the built-in `__proto__` getter/setter isn't recommended, it's now in the Annex B of the specification. +- At få eller sætte en prototype ved hjælp af de indbyggede `__proto__` getter/setter anbefales ikke, da det nu er i Annex B af specifikationen. -- We also covered prototype-less objects, created with `Object.create(null)` or `{__proto__: null}`. +- Vi dækkede også objekter uden prototype, oprettet med `Object.create(null)` eller `{__proto__: null}`. - These objects are used as dictionaries, to store any (possibly user-generated) keys. + Disse objekter bruges som "dictionary" (ordbøger) til at gemme enhver (muligvis bruger-genereret) nøgle. - Normally, objects inherit built-in methods and `__proto__` getter/setter from `Object.prototype`, making corresponding keys "occupied" and potentially causing side effects. With `null` prototype, objects are truly empty. + Normalt arver objekter indbyggede metoder og `__proto__` getter/setter fra `Object.prototype`, hvilket gør de tilsvarende nøgler "optaget" og potentielt forårsager sideeffekter. Med `null` prototype er objekterne virkelig tomme. diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/task.md b/1-js/09-classes/01-class/1-rewrite-to-class/task.md index 4477de679..5c7012767 100644 --- a/1-js/09-classes/01-class/1-rewrite-to-class/task.md +++ b/1-js/09-classes/01-class/1-rewrite-to-class/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# Rewrite to class +# Omskriv til en klasse -The `Clock` class (see the sandbox) is written in functional style. Rewrite it in the "class" syntax. +Klassen `Clock` (se i sandkassen) er skrevet med funktioner. Omskriv den til "class" syntaks. -P.S. The clock ticks in the console, open it to see. +P.S. Klokken tikker i konsollen, åbn den for at se. diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md index 135d24929..c0501fe7a 100644 --- a/1-js/09-classes/01-class/article.md +++ b/1-js/09-classes/01-class/article.md @@ -1,19 +1,19 @@ -# Class basic syntax +# Klasser: Grundlæggende syntaks ```quote author="Wikipedia" -In object-oriented programming, a *class* is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods). +I objekt-orienteret programmering, er en *klasse* (class) en udvidelig program-kodetemplate til at skabe objekter, der giver initiale værdier for tilstand (medlemsvariable) og implementeringer af adfærd (medlemsfunktioner eller metoder). ``` -In practice, we often need to create many objects of the same kind, like users, or goods or whatever. +I praksis har vi ofte brug for at skabe mange objekter af samme type, som f.eks. brugere eller varer eller hvad som helst. -As we already know from the chapter , `new function` can help with that. +Som vi allerede ved fra kapitlet , kan `new function` hjælpe med det. -But in the modern JavaScript, there's a more advanced "class" construct, that introduces great new features which are useful for object-oriented programming. +Men i moderne JavaScript, er der en mere avanceret "class" konstruktion, der introducerer store nye funktioner, som er nyttige for objekt-orienteret programmering. -## The "class" syntax +## Syntaks for "class" -The basic syntax is: +Den grundlæggende syntaks er: ```js class MyClass { // class methods @@ -25,11 +25,11 @@ class MyClass { } ``` -Then use `new MyClass()` to create a new object with all the listed methods. +Derefter bruges `new MyClass()` til at oprette et nyt objekt med alle de opførte metoder. -The `constructor()` method is called automatically by `new`, so we can initialize the object there. +Metoden `constructor()` kaldes automatisk af `new`, så vi kan initialisere objektet der. -For example: +For eksempel: ```js run class User { @@ -45,32 +45,32 @@ class User { } // Usage: -let user = new User("John"); +let user = new User("Karsten"); user.sayHi(); ``` -When `new User("John")` is called: -1. A new object is created. -2. The `constructor` runs with the given argument and assigns it to `this.name`. +Når `new User("Karsten")` kaldes, sker der følgende: +1. Et nyt objekt oprettes. +2. Metoden `constructor` kører med det givne argument og tildeler det til `this.name`. -...Then we can call object methods, such as `user.sayHi()`. +...efter det kan vi kalde objektets metoder, såsom `user.sayHi()`. -```warn header="No comma between class methods" -A common pitfall for novice developers is to put a comma between class methods, which would result in a syntax error. +```warn header="Ingen komma mellem class metoder" +En kendt fejl i begyndelsen er at putte kommaer mellem class metoder - det vil føre tilen syntaksfejl. -The notation here is not to be confused with object literals. Within the class, no commas are required. +Den notation her er ikke at forveksle med object literals. Inden for class, er kommaer ikke nødvendige. ``` -## What is a class? +## Hvad er en class? -So, what exactly is a `class`? That's not an entirely new language-level entity, as one might think. +Så, hvad er `class` egentlig for en størrelse? Det er faktisk ikke så nyt et koncept på sprogniveau, som man måske skulle forestille sig. -Let's unveil any magic and see what a class really is. That'll help in understanding many complex aspects. +Lad os prøve at pakke det ud lidt ad gangen. Det vil hjælpe med at forstå de mere komplekse aspekter. -In JavaScript, a class is a kind of function. +I JavaScript er en klasse en slags funktion. -Here, take a look: +Lad os se på følgende: ```js run class User { @@ -78,24 +78,24 @@ class User { sayHi() { alert(this.name); } } -// proof: User is a function +// Bevis: User er en function *!* alert(typeof User); // function */!* ``` -What `class User {...}` construct really does is: +Det konstruktionen `class User {...}` i virkeligheden gør er: -1. Creates a function named `User`, that becomes the result of the class declaration. The function code is taken from the `constructor` method (assumed empty if we don't write such method). -2. Stores class methods, such as `sayHi`, in `User.prototype`. +1. Opretter en funktion kaldet `User`, som bliver resultatet af class-deklarationen. Funktionens kode bliver taget fra `constructor`-metoden (antaget tom, hvis vi ikke skriver en sådan). +2. Gemmer class-metoder, såsom `sayHi`, i `User.prototype`. -After `new User` object is created, when we call its method, it's taken from the prototype, just as described in the chapter . So the object has access to class methods. +Efter at et `new User`-objekt er oprettet, når vi kalder dens metode, bliver den taget fra prototype, ligesom beskrevet i kapitlet . Så har objektet adgang til class-metoder. -We can illustrate the result of `class User` declaration as: +Vi kan illustrere resultatet af `class User`-deklarationen som: ![](class-user.svg) -Here's the code to introspect it: +Her er koden til at kigge nærmere på det: ```js run class User { @@ -103,50 +103,50 @@ class User { sayHi() { alert(this.name); } } -// class is a function +// class er en function alert(typeof User); // function -// ...or, more precisely, the constructor method +// ...eller, mere præcist, konstruktøren alert(User === User.prototype.constructor); // true -// The methods are in User.prototype, e.g: -alert(User.prototype.sayHi); // the code of the sayHi method +// Metoderne findes i User.prototype, f. eks. sayHi: +alert(User.prototype.sayHi); // her er koden for metoden sayHi -// there are exactly two methods in the prototype +// der er præcis to metoder i prototypen alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi ``` -## Not just a syntactic sugar +## Det er ikke kun en syntactic sugar -Sometimes people say that `class` is a "syntactic sugar" (syntax that is designed to make things easier to read, but doesn't introduce anything new), because we could actually declare the same thing without using the `class` keyword at all: +Du vil høre folk sige at `class` er en "syntactic sugar" (syntaks der er designet til at gøre ting lettere at læse, men ikke introducerer noget nyt), fordi vi faktisk kunne erklære det samme uden at bruge `class`-nøgleordet: ```js run -// rewriting class User in pure functions +// omskrivning af class User til kun at bruge funktioner -// 1. Create constructor function +// 1. Opret constructor function User(name) { this.name = name; } -// a function prototype has "constructor" property by default, -// so we don't need to create it +// En function prototype har egenskaben "constructor" som standard, +// så vi behøver ikke at oprette den -// 2. Add the method to prototype +// 2. Tilføj metoden til prototype User.prototype.sayHi = function() { alert(this.name); }; -// Usage: -let user = new User("John"); +// Brug: +let user = new User("Karsten"); user.sayHi(); ``` -The result of this definition is about the same. So, there are indeed reasons why `class` can be considered a syntactic sugar to define a constructor together with its prototype methods. +Resultatet af denne definition er omkring det samme. Så, der er faktisk grunde til at `class` kan betragtes som en syntactic sugar til at definere en constructor sammen med dens prototype metoder. -Still, there are important differences. +Alligevel, der er vigtige forskelle. -1. First, a function created by `class` is labelled by a special internal property `[[IsClassConstructor]]: true`. So it's not entirely the same as creating it manually. +1. Først, en funktion oprettet af `class` er mærket med en speciel intern egenskab `[[IsClassConstructor]]: true`. Så det er ikke helt det samme som at oprette den manuelt. - The language checks for that property in a variety of places. For example, unlike a regular function, it must be called with `new`: + SProget tjekker for denne egenskab i en række sammenhænge. For eksempel, i modsætning til en almindelig funktion, skal den kaldes med `new`: ```js run class User { @@ -157,7 +157,7 @@ Still, there are important differences. User(); // Error: Class constructor User cannot be invoked without 'new' ``` - Also, a string representation of a class constructor in most JavaScript engines starts with the "class..." + Derudover vil en repræsentation af klassen som en streng i de fleste JavaScript-motorer starte med "class..." ```js run class User { @@ -166,23 +166,23 @@ Still, there are important differences. alert(User); // class User { ... } ``` - There are other differences, we'll see them soon. + Der er også andre forskelle som vi snart vil se. -2. Class methods are non-enumerable. - A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`. +2. Class metoder er ikke-enumerable. + En class definition sætter flaget `enumerable` til `false` for alle metoder i dens `"prototype"`. - That's good, because if we `for..in` over an object, we usually don't want its class methods. + Det er godt, fordi hvis vi bruger `for..in` på et objekt, vil vi normalt ikke vil have dets class metoder. -3. Classes always `use strict`. - All code inside the class construct is automatically in strict mode. +3. Class bruger altid `use strict`. + Al kode inde i en class konstruktion er automatisk sat til strict mode. -Besides, `class` syntax brings many other features that we'll explore later. +Der er også andre features ved `class` syntaksen som vi kigger på senere. ## Class Expression -Just like functions, classes can be defined inside another expression, passed around, returned, assigned, etc. +På samme måde som funktioner, kan classes defineres indeni en andet udtryk (expression), videregives, returneres, tildeles osv. -Here's an example of a class expression: +Her er et eksempel på en class expression: ```js let User = class { @@ -192,29 +192,29 @@ let User = class { }; ``` -Similar to Named Function Expressions, class expressions may have a name. +På samme måde som "Named Function Expressions", kan class udtryk også have et navn. -If a class expression has a name, it's visible inside the class only: +Hvis et class udtryk har et navn, er det kun synligt inden for klassen selv: ```js run // "Named Class Expression" -// (no such term in the spec, but that's similar to Named Function Expression) +// (der er ikke sådan et navn i specifikationen, men det er det samme som med Named Function Expression) let User = class *!*MyClass*/!* { sayHi() { - alert(MyClass); // MyClass name is visible only inside the class + alert(MyClass); // Navnet MyClass er kun synligt inden for klassen selv } }; -new User().sayHi(); // works, shows MyClass definition +new User().sayHi(); // virker, viser MyClass definition -alert(MyClass); // error, MyClass name isn't visible outside of the class +alert(MyClass); // fejl, navnet MyClass er ikke synligt uden for klassen ``` -We can even make classes dynamically "on-demand", like this: +Vi kan endda oprette klasser dynamisk "on-demand", som dette: ```js run function makeClass(phrase) { - // declare a class and return it + // deklarerer en klasse og returner den return class { sayHi() { alert(phrase); @@ -222,24 +222,24 @@ function makeClass(phrase) { }; } -// Create a new class -let User = makeClass("Hello"); +// Opret en ny klasse +let User = makeClass("Hej!"); -new User().sayHi(); // Hello +new User().sayHi(); // Hej! ``` ## Getters/setters -Just like literal objects, classes may include getters/setters, computed properties etc. +På samme måde som med objekter kan klasser have getters og setters, computed properties osv. -Here's an example for `user.name` implemented using `get/set`: +Her er et eksempel for `user.name` implementeret ved hjælp af `get/set`: ```js run class User { constructor(name) { - // invokes the setter + // aktiverer dens setter this.name = name; } @@ -253,7 +253,7 @@ class User { set name(value) { */!* if (value.length < 4) { - alert("Name is too short."); + alert("Navnet er for kort."); return; } this._name = value; @@ -261,17 +261,17 @@ class User { } -let user = new User("John"); -alert(user.name); // John +let user = new User("Karsten"); +alert(user.name); // Karsten -user = new User(""); // Name is too short. +user = new User("Bo"); // Navnet er for kort. ``` -Technically, such class declaration works by creating getters and setters in `User.prototype`. +Teknisk set virker sådanne deklarationer ved at oprette getter og setter i `User.prototype`. ## Computed names [...] -Here's an example with a computed method name using brackets `[...]`: +Her er et eksempel hvor navnet på metoden er udregnet ved hjælp af brackets `[...]`: ```js run class User { @@ -279,7 +279,7 @@ class User { *!* ['say' + 'Hi']() { */!* - alert("Hello"); + alert("Hej"); } } @@ -287,71 +287,71 @@ class User { new User().sayHi(); ``` -Such features are easy to remember, as they resemble that of literal objects. +Nogle muligheder er nemme at huske, da de minder om dem fra normale objekter. ## Class fields -```warn header="Old browsers may need a polyfill" -Class fields are a recent addition to the language. +```warn header="Ældre browsere kan have brug for et polyfill" +Class fields er en relativ ny feature i JavaScript. ``` -Previously, our classes only had methods. +Tidligere havde klasser kun metoder. -"Class fields" is a syntax that allows to add any properties. +"Class fields" er en syntaks der tillader os at tilføje vilkårlige egenskaber. -For instance, let's add `name` property to `class User`: +For eksempel, lad os tilføje egenskaben `name` til `class User`: ```js run class User { *!* - name = "John"; + name = "Karsten"; */!* sayHi() { - alert(`Hello, ${this.name}!`); + alert(`Hej ${this.name}!`); } } -new User().sayHi(); // Hello, John! +new User().sayHi(); // Hej Karsten! ``` -So, we just write " = " in the declaration, and that's it. +Så vi skriver simpelthen " = " i deklarationen, og det er det. -The important difference of class fields is that they are set on individual objects, not `User.prototype`: +En vigtig forskel mellem class fields og almindelige metoder er, at de er sat på individuelle objekter, ikke `User.prototype`: ```js run class User { *!* - name = "John"; + name = "Karsten"; */!* } let user = new User(); -alert(user.name); // John +alert(user.name); // Karsten alert(User.prototype.name); // undefined ``` -We can also assign values using more complex expressions and function calls: +Vi kan også tildele værdier ved hjælp af mere komplekse udtryk og funktionskald: ```js run class User { *!* - name = prompt("Name, please?", "John"); + name = prompt("Dit navn, tak?", "Karsten"); */!* } let user = new User(); -alert(user.name); // John +alert(user.name); // Karsten ``` -### Making bound methods with class fields +### Gør bundne metoder til class fields -As demonstrated in the chapter functions in JavaScript have a dynamic `this`. It depends on the context of the call. +Som demonstreret i kapitlet har funktioner i JavaScript en dynamisk `this`. Det afhænger af konteksten for kaldet. -So if an object method is passed around and called in another context, `this` won't be a reference to its object any more. +Så hvis en objektmetode bliver videregivet og kaldt i en anden kontekst, vil `this` ikke længere være en reference til objektet. -For instance, this code will show `undefined`: +For eksempel vil denne kode vise `undefined`: ```js run class Button { @@ -364,21 +364,21 @@ class Button { } } -let button = new Button("hello"); +let button = new Button("hej"); *!* setTimeout(button.click, 1000); // undefined */!* ``` -The problem is called "losing `this`". +Problemet kaldes populært at den "mister `this`" ("losing `this`"). -There are two approaches to fixing it, as discussed in the chapter : +Der er to tilgange til at fikse det, som vi diskuterede i kapitlet : -1. Pass a wrapper-function, such as `setTimeout(() => button.click(), 1000)`. -2. Bind the method to object, e.g. in the constructor. +1. Videregiv en wrapper-funktion, i stil med `setTimeout(() => button.click(), 1000)`. +2. Bind metoden til objektet, f.eks. i constructor. -Class fields provide another, quite elegant syntax: +Class fields leverer en anden, ganske elegant syntaks: ```js run class Button { @@ -392,37 +392,37 @@ class Button { */!* } -let button = new Button("hello"); +let button = new Button("hej"); -setTimeout(button.click, 1000); // hello +setTimeout(button.click, 1000); // hej ``` -The class field `click = () => {...}` is created on a per-object basis, there's a separate function for each `Button` object, with `this` inside it referencing that object. We can pass `button.click` around anywhere, and the value of `this` will always be correct. +class field `click = () => {...}` oprettes på individuelle objekter, så der er en seperat funktion for hver `Button`-objekt, med `this` inde i den, der refererer til det objekt. Vi kan overføre `button.click` hvor som helst, og værdien af `this` vil altid være korrekt. -That's especially useful in browser environment, for event listeners. +Det er især nyttigt i browser-miljøet, for event-listeners. -## Summary +## Opsummering -The basic class syntax looks like this: +Den grundlæggende syntaks for klasser ser sådan ud: ```js class MyClass { - prop = value; // property + prop = value; // egenskab (class field) constructor(...) { // constructor // ... } - method(...) {} // method + method(...) {} // metode - get something(...) {} // getter method - set something(...) {} // setter method + get something(...) {} // getter metode + set something(...) {} // setter metode - [Symbol.iterator]() {} // method with computed name (symbol here) + [Symbol.iterator]() {} // metode med beregnet navn (symbol her) // ... } ``` -`MyClass` is technically a function (the one that we provide as `constructor`), while methods, getters and setters are written to `MyClass.prototype`. +`MyClass` er teknisk set en function (den vi leverer som `constructor`), mens metoder, getters og setters skrives i `MyClass.prototype`. -In the next chapters we'll learn more about classes, including inheritance and other features. +I de næste kapitler vil vi lære mere om klasser, nedarvning og andre funktioner. diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md index 4711e4827..cd5e25d7a 100644 --- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md +++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md @@ -1,6 +1,6 @@ -That's because the child constructor must call `super()`. +Det er fordi at konstruktøren skal kalde `super()`. -Here's the corrected code: +Her er den tilrettede kode: ```js run class Animal { @@ -21,7 +21,7 @@ class Rabbit extends Animal { } *!* -let rabbit = new Rabbit("White Rabbit"); // ok now +let rabbit = new Rabbit("Hvid kanin"); // ok nu */!* -alert(rabbit.name); // White Rabbit +alert(rabbit.name); // Hvid kanin ``` diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md index 380a4720b..827a37175 100644 --- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md +++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Error creating an instance +# Fejl ved oprettelse af instans -Here's the code with `Rabbit` extending `Animal`. +Her er koden hvor `Rabbit` udvider `Animal`. -Unfortunately, `Rabbit` objects can't be created. What's wrong? Fix it. +Uheldigvis kan `Rabbit`-objekter ikke oprettes. Hvad er galt? Ret det. ```js run class Animal { @@ -24,7 +24,7 @@ class Rabbit extends Animal { } *!* -let rabbit = new Rabbit("White Rabbit"); // Error: this is not defined +let rabbit = new Rabbit("Hvid kanin"); // Fejl: this is not defined */!* alert(rabbit.name); ``` diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html index c0609858b..b0c0ab456 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html @@ -1,13 +1,12 @@ - +