From c07df985f1466751eff45c881c3ac5460dcbdb22 Mon Sep 17 00:00:00 2001 From: Travis Briggs Date: Mon, 22 Jul 2024 18:57:50 -0700 Subject: [PATCH 01/13] Update article.md Remove non-inclusive language. --- 1-js/01-getting-started/1-intro/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 2f4f518f..a58d5d72 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -73,7 +73,7 @@ Examples of such restrictions include: This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and must contain special JavaScript code that handles it. We'll cover that in the tutorial. This limitation is, again, for the user's safety. A page from `http://anysite.com` which a user has opened must not be able to access another browser tab with the URL `http://gmail.com`, for example, and steal information from there. -- JavaScript can easily communicate over the net to the server where the current page came from. But its ability to receive data from other sites/domains is crippled. Though possible, it requires explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's a safety limitation. +- JavaScript can easily communicate over the net to the server where the current page came from. But its ability to receive data from other sites/domains is severely limited. Though possible, it requires explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's a safety limitation. ![](limitations.svg) From 5f40ec4eff039a06a9886161b1bf5b0b45260e2f Mon Sep 17 00:00:00 2001 From: ockley Date: Fri, 6 Mar 2026 13:13:33 +0100 Subject: [PATCH 02/13] Oversat til dansk --- .../2-dictionary-tostring/solution.md | 20 +-- .../2-dictionary-tostring/task.md | 20 +-- .../3-compare-calls/solution.md | 8 +- .../3-compare-calls/task.md | 8 +- .../04-prototype-methods/article.md | 160 +++++++++--------- 5 files changed, 108 insertions(+), 108 deletions(-) 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 f3c9cf0e..234388df 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 0d831f2c..82521674 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 90d3118b..995c79f2 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 09bb7f1e..672883d4 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 9c5f1eb3..3b54e6a9 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. From d7531fecfbc385f56980738b2229392d8ae8fe1c Mon Sep 17 00:00:00 2001 From: ockley Date: Fri, 6 Mar 2026 14:04:05 +0100 Subject: [PATCH 03/13] oversat til dansk --- .../01-class/1-rewrite-to-class/task.md | 6 +- 1-js/09-classes/01-class/article.md | 236 +++++++++--------- 1-js/09-classes/index.md | 2 +- 3 files changed, 122 insertions(+), 122 deletions(-) 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 4477de67..5c701276 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 135d2492..c0501fe7 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/index.md b/1-js/09-classes/index.md index 87846ef6..70a9e4cd 100644 --- a/1-js/09-classes/index.md +++ b/1-js/09-classes/index.md @@ -1 +1 @@ -# Classes +# Klasser From eda3795e21f1934c4b5f104fe589062ddaff072d Mon Sep 17 00:00:00 2001 From: ockley Date: Sat, 7 Mar 2026 14:54:46 +0100 Subject: [PATCH 04/13] Oversat til dansk --- .../1-class-constructor-error/solution.md | 8 +- .../1-class-constructor-error/task.md | 8 +- .../source.view/index.html | 7 +- .../2-clock-class-extended/task.md | 10 +- .../animal-rabbit-extends.svg | 107 ++++- .../02-class-inheritance/article.md | 376 +++++++++--------- .../class-inheritance-rabbit-animal-2.svg | 90 ++++- .../rabbit-animal-independent-animal.svg | 63 ++- .../rabbit-animal-independent-rabbit.svg | 61 ++- 9 files changed, 521 insertions(+), 209 deletions(-) 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 4711e482..cd5e25d7 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 380a4720..827a3717 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 c0609858..b0c0ab45 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 @@ - + From d82d85f9b938b51e94142ac0205321272ced9d78 Mon Sep 17 00:00:00 2001 From: ockley Date: Fri, 20 Mar 2026 15:51:22 +0100 Subject: [PATCH 12/13] oversat til dansk --- .../1-finally-or-code-after/solution.md | 24 +- .../1-finally-or-code-after/task.md | 22 +- 1-js/10-error-handling/1-try-catch/article.md | 391 +++++++++--------- .../1-try-catch/try-catch-flow.svg | 92 ++++- 4 files changed, 309 insertions(+), 220 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md index ec0dabc9..20f36734 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md @@ -1,47 +1,47 @@ -The difference becomes obvious when we look at the code inside a function. +Forskellen bliver tydelig, når vi kigger på koden inde i en funktion. -The behavior is different if there's a "jump out" of `try...catch`. +Det er forskelligt, hvis der er et "spring ud" af `try...catch`. -For instance, when there's a `return` inside `try...catch`. The `finally` clause works in case of *any* exit from `try...catch`, even via the `return` statement: right after `try...catch` is done, but before the calling code gets the control. +For eksempel, når der er en `return` inde i `try...catch`. `finally`-klausulen virker i tilfældet af *hvilken som helst* afslutning fra `try...catch`, selv via `return`-sætningen: lige efter `try...catch` er færdig, men før den kaldende kode får kontrollen. ```js run function f() { try { alert('start'); *!* - return "result"; + return "resultat"; */!* } catch (err) { /// ... } finally { - alert('cleanup!'); + alert('oprydning!'); } } -f(); // cleanup! +f(); // oprydning! ``` -...Or when there's a `throw`, like here: +...eller hvis der er en `throw`, som her: ```js run function f() { try { alert('start'); - throw new Error("an error"); + throw new Error("en fejl"); } catch (err) { // ... - if("can't handle the error") { + if("kan ikke håndtere fejlen") { *!* throw err; */!* } } finally { - alert('cleanup!') + alert('oprydning!') } } -f(); // cleanup! +f(); // oprydning! ``` -It's `finally` that guarantees the cleanup here. If we just put the code at the end of `f`, it wouldn't run in these situations. +Det er `finally` der garanterer oprydningen her. Hvis vi bare sætter koden ved slutningen af `f`, ville den ikke køre i disse situationer. diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md index b6dc8132..c5663cba 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md @@ -4,35 +4,35 @@ importance: 5 # Finally or just the code? -Compare the two code fragments. +Sammenlign disse to kodefragmenter. -1. The first one uses `finally` to execute the code after `try...catch`: +1. Den første bruger `finally` til at køre koden efter `try...catch`: ```js try { - work work + arbejd' arbejd' } catch (err) { - handle errors + håndter fejl } finally { *!* - cleanup the working space + ryd op på arbejdspladsen */!* } ``` -2. The second fragment puts the cleaning right after `try...catch`: +2. Den anden placerer oprydningen lige efter `try...catch`: ```js try { - work work + arbejd' arbejd' } catch (err) { - handle errors + håndter fejl } *!* - cleanup the working space + ryd op på arbejdspladsen */!* ``` -We definitely need the cleanup after the work, doesn't matter if there was an error or not. +Vi skal selvfølgelig have oprydningen efter arbejdet, uanset om der var en fejl eller ej. -Is there an advantage here in using `finally` or both code fragments are equal? If there is such an advantage, then give an example when it matters. +Er der en fordel i at bruge `finally` eller er de to kodefragmenter ens? Hvis der er en sådan fordel, så giv et eksempel på, når det betyder noget. diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index cad2e1a3..a8bf2b7b 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -1,98 +1,98 @@ -# Error handling, "try...catch" +# Håndtering af fejl, "try...catch" -No matter how great we are at programming, sometimes our scripts have errors. They may occur because of our mistakes, an unexpected user input, an erroneous server response, and for a thousand other reasons. +Uanset hvor gode vi er til programmering, så har vores scripts periodisk fejl. De kan opstå på grund af vores fejl, et uventet brugerinput, et fejlbehæftet server svar, og for tusind andre grunde. -Usually, a script "dies" (immediately stops) in case of an error, printing it to console. +Normalt dør et script (stoppes øjeblikkeligt) når en fejl opstår, og fejlen udskrives til konsollen. -But there's a syntax construct `try...catch` that allows us to "catch" errors so the script can, instead of dying, do something more reasonable. +Men der er en konstruktion `try...catch` som tillader os at "fange" fejl, så scriptet kan gøre noget mere fornuftigt end at dø. -## The "try...catch" syntax +## Syntaksen "try...catch" -The `try...catch` construct has two main blocks: `try`, and then `catch`: +Konstruktionen `try...catch` har to hovedblokke: `try`, og derefter `catch`: ```js try { - // code... + // kode... } catch (err) { - // error handling + // fejlhåndtering } ``` -It works like this: +Det virker sådan: -1. First, the code in `try {...}` is executed. -2. If there were no errors, then `catch (err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`. -3. If an error occurs, then the `try` execution is stopped, and control flows to the beginning of `catch (err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened. +1. Først vil koden i `try {...}` blive kørt. +2. Hvis der ikke er nogen fejl, så ignoreres `catch (err)`: eksekveringen når til slutningen af `try` og går videre, springer over `catch`. +3. Hvis en fejl opstår, så stoppes `try`-eksekveringen, og kontrol flyttes til begyndelsen af `catch (err)`. Den `err`-variabel (vi kan bruge et hvilket som helst navn) vil indeholde et fejlobjekt med detaljer om, hvad der skete. ![](try-catch-flow.svg) -So, an error inside the `try {...}` block does not kill the script -- we have a chance to handle it in `catch`. +Så, hvis der sker en fejl inde i `try {...}` blokken, så dør scriptet ikke -- vi har en chance til at håndtere den i `catch`. -Let's look at some examples. +Lad os se på et par eksempler. -- An errorless example: shows `alert` `(1)` and `(2)`: +- Et eksempel uden fejl: viser `alert` `(1)` og `(2)`: ```js run try { - alert('Start of try runs'); // *!*(1) <--*/!* + alert('Start på "try runs"'); // *!*(1) <--*/!* - // ...no errors here + // ...ingen fejl her - alert('End of try runs'); // *!*(2) <--*/!* + alert('Slut på "try runs"'); // *!*(2) <--*/!* } catch (err) { - alert('Catch is ignored, because there are no errors'); // (3) + alert('Catch ignoreres fordi der ikke var fejl'); // (3) } ``` -- An example with an error: shows `(1)` and `(3)`: +- Et eksempel med en fejl: viser `(1)` og `(3)`: ```js run try { - alert('Start of try runs'); // *!*(1) <--*/!* + alert('Start på "try runs"'); // *!*(1) <--*/!* *!* - lalala; // error, variable is not defined! + lalala; // fejl, variable is not defined! */!* - alert('End of try (never reached)'); // (2) + alert('Slut på "try runs"'); // (2) } catch (err) { - alert(`Error has occurred!`); // *!*(3) <--*/!* + alert(`Der skete en fejl!`); // *!*(3) <--*/!* } ``` -````warn header="`try...catch` only works for runtime errors" -For `try...catch` to work, the code must be runnable. In other words, it should be valid JavaScript. +````warn header="`try...catch` virker kun for runtime errors" +For at `try...catch` skal virke skal koden kunne køre. Med anre ord skal det være gyldig (valid) JavaScript. -It won't work if the code is syntactically wrong, for instance it has unmatched curly braces: +Den virker ikke hvis syntaksen er forkert. For eksempel hvis der er rod med parenteser: ```js run try { {{{{{{{{{{{{ } catch (err) { - alert("The engine can't understand this code, it's invalid"); + alert("Motoren forstår ikke denne kode, den er ugyldig"); } ``` -The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code. +JavaScript-motoren læser koden først, og derefter kører den. De fejl, der opstår under læsningen, kaldes "parse-time" fejl og er unrecoverable (fra inde i koden). Det er fordi motoren ikke kan forstå koden. -So, `try...catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions". -```` +Så, `try...catch` kan kun håndtere fejl, der opstår i gyldig kode. Sådanne fejl kaldes "runtime errors" eller, nogle gange, "exceptions". +``` -````warn header="`try...catch` works synchronously" -If an exception happens in "scheduled" code, like in `setTimeout`, then `try...catch` won't catch it: +````warn header="`try...catch` virker synkront" +Hvis en exception opstår i "planlagt" kode, som i `setTimeout`, så vil `try...catch` ikke fange den: ```js run try { @@ -100,112 +100,112 @@ try { noSuchVariable; // script will die here }, 1000); } catch (err) { - alert( "won't work" ); + alert( "det her virker ikke" ); } ``` -That's because the function itself is executed later, when the engine has already left the `try...catch` construct. +Det er fordi at selve funktionen først afvikles senere - det har motoren allerede forladt `try...catch` konstruktionen. -To catch an exception inside a scheduled function, `try...catch` must be inside that function: +For at fange en exception inde i en planlagt funktion, skal `try...catch` være inde i selve funktionen: ```js run setTimeout(function() { try { - noSuchVariable; // try...catch handles the error! + noSuchVariable; // try...catch håndterer fejlen! } catch { - alert( "error is caught here!" ); + alert( "fejlen fanges her!" ); } }, 1000); ``` ```` -## Error object +## Error objekt -When an error occurs, JavaScript generates an object containing the details about it. The object is then passed as an argument to `catch`: +Når der opstår en fejl, genererer JavaScript et objekt, der indeholder detaljerne om fejlen. Objektet sendes derefter som et argument til `catch`: ```js try { // ... -} catch (err) { // <-- the "error object", could use another word instead of err +} catch (err) { // <-- her er "error objektet", du kan sagtens bruge et andet navn istedet for err // ... } ``` -For all built-in errors, the error object has two main properties: +For alle indbyggede fejl har error objektet to hovedegenskaber: `name` -: Error name. For instance, for an undefined variable that's `"ReferenceError"`. +: Navnet på fejlen. Hvis det for eksempel er en ikke-defineret variabel, så indeholder den `"ReferenceError"`. `message` -: Textual message about error details. +: En tekst der beskriver fejlen. -There are other non-standard properties available in most environments. One of most widely used and supported is: +Der er andre ikke-standard egenskaber tilgængelige i de fleste miljøer. En af de mest brugte og understøttede er: `stack` -: Current call stack: a string with information about the sequence of nested calls that led to the error. Used for debugging purposes. +: Aktuel kaldestak: en streng med information om sekvensen af indlejrede kald, der ledte til fejlen. Bruges til fejlfinding. -For instance: +For eksempel: ```js run untrusted try { *!* - lalala; // error, variable is not defined! + lalala; // fejl, variablen er ikke defineret! */!* } catch (err) { alert(err.name); // ReferenceError alert(err.message); // lalala is not defined alert(err.stack); // ReferenceError: lalala is not defined at (...call stack) - // Can also show an error as a whole - // The error is converted to string as "name: message" + // Kan også vise en fejl som et samlet output + // Fejlen konverteres til en streng som "name: message" alert(err); // ReferenceError: lalala is not defined } ``` -## Optional "catch" binding +## Frivillig "catch" binding [recent browser=new] -If we don't need error details, `catch` may omit it: +Hvis vi ikke behøver detaljer om fejlen, kan `catch` udelade den: ```js try { // ... -} catch { // <-- without (err) +} catch { // <-- uden (err) // ... } ``` -## Using "try...catch" +## Brug af "try...catch" -Let's explore a real-life use case of `try...catch`. +Lad os udforske brugsscenarier for `try...catch`. -As we already know, JavaScript supports the [JSON.parse(str)](mdn:js/JSON/parse) method to read JSON-encoded values. +Som vi allerede ved så understøtter JavaScript metoden [JSON.parse(str)](mdn:js/JSON/parse) til at læse JSON værdier. -Usually it's used to decode data received over the network, from the server or another source. +Normalt bruges den til at afkode data der er modtaget over netværket, fra serveren eller anden kilde. -We receive it and call `JSON.parse` like this: +Vi modtager det og kalder `JSON.parse` sådan her: ```js run let json = '{"name":"John", "age": 30}'; // data from the server *!* -let user = JSON.parse(json); // convert the text representation to JS object +let user = JSON.parse(json); // konverterer tekstrepræsentation til JS-objekt */!* -// now user is an object with properties from the string +// nu er user et objekt med egenskaber fra strengen alert( user.name ); // John alert( user.age ); // 30 ``` -You can find more detailed information about JSON in the chapter. +Du kan finde mere detaljeret information om JSON i kapitlet . -**If `json` is malformed, `JSON.parse` generates an error, so the script "dies".** +**Hvis `json` indeholder fejl vil `JSON.parse` generere en fejl, så scriptet "dør".** -Should we be satisfied with that? Of course not! +Skal vi stille os tilfreds med det? Nej, selvfølgelig ikke! -This way, if something's wrong with the data, the visitor will never know that (unless they open the developer console). And people really don't like when something "just dies" without any error message. +På denne måde, hvis der er noget galt med data, vil besøgende aldrig vide det (medmindre de åbner konsollen). Og folk kan ikke li', når noget "bare dør" uden nogen fejlbesked. -Let's use `try...catch` to handle the error: +Lad os bruge `try...catch` til at håndtere fejlen: ```js run let json = "{ bad json }"; @@ -213,74 +213,74 @@ let json = "{ bad json }"; try { *!* - let user = JSON.parse(json); // <-- when an error occurs... + let user = JSON.parse(json); // <-- når en fejl opstår... */!* - alert( user.name ); // doesn't work + alert( user.name ); // virker ikke } catch (err) { *!* - // ...the execution jumps here - alert( "Our apologies, the data has errors, we'll try to request it one more time." ); + // ...hopper afviklingen her til + alert( "Desværre indeholder vores data fejl, vi vil forsøge at anmode om den en gang til." ); alert( err.name ); alert( err.message ); */!* } ``` -Here we use the `catch` block only to show the message, but we can do much more: send a new network request, suggest an alternative to the visitor, send information about the error to a logging facility, ... . All much better than just dying. +Her bruger vi kun `catch` blokken til at vise en besked, men vi kan gøre meget andet: sende et nyt netværkskald, foreslå et alternativ til besøgende, send information om fejlen til en log, ... alle muligheder der er meget bedre end bare at dø. -## Throwing our own errors +## Kaste vores egne fejl -What if `json` is syntactically correct, but doesn't have a required `name` property? +Hvad hvis `json` er syntactisk korrekt, men ikke har en påkrævet `name` egenskab? -Like this: +Som dette: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // ufuldstændige data try { - let user = JSON.parse(json); // <-- no errors + let user = JSON.parse(json); // <-- ingen fejl *!* - alert( user.name ); // no name! + alert( user.name ); // intet navn! */!* } catch (err) { - alert( "doesn't execute" ); + alert( "afvikles ikke" ); } ``` -Here `JSON.parse` runs normally, but the absence of `name` is actually an error for us. +Her kører `JSON.parse` normalt, men fraværet af `name` er faktisk en fejl for os. -To unify error handling, we'll use the `throw` operator. +For at ensrette fejlhåndteringen, vil vi bruge `throw` operatoren. ### "Throw" operator -The `throw` operator generates an error. +Operatoren `throw` genererer en fejl. -The syntax is: +Syntaksen er: ```js throw ``` -Technically, we can use anything as an error object. That may be even a primitive, like a number or a string, but it's better to use objects, preferably with `name` and `message` properties (to stay somewhat compatible with built-in errors). +Teknisk set kan vi kaste hvad som helst som et error objekt. Det kan endda være en primitiv, som et tal eller en streng, men det er bedre at bruge objekter, især med `name` og `message` egenskaber (for at forblive nogenlunde kompatibel med de indbyggede fejl). -JavaScript has many built-in constructors for standard errors: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` and others. We can use them to create error objects as well. +JavaScript har mange indbyggede konstruktører for standardfejl: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` og andre. Vi kan bruge dem til at oprette fejlobjekter. -Their syntax is: +Deres syntaks er: ```js let error = new Error(message); -// or +// eller let error = new SyntaxError(message); let error = new ReferenceError(message); // ... ``` -For built-in errors (not for any objects, just for errors), the `name` property is exactly the name of the constructor. And `message` is taken from the argument. +For indbyggede fejl (ikke for objekter generelt, kun for fejl) er `name` egenskaben præcis det samme som navnet på konstruktøren, og `message` er taget fra argumentet. -For instance: +For eksempel: ```js run let error = new Error("Things happen o_O"); @@ -289,7 +289,7 @@ alert(error.name); // Error alert(error.message); // Things happen o_O ``` -Let's see what kind of error `JSON.parse` generates: +Lad os se hvilken fejl `JSON.parse` genererer, når den ikke kan læse data: ```js run try { @@ -302,14 +302,14 @@ try { } ``` -As we can see, that's a `SyntaxError`. +Som vi kan se er det en `SyntaxError`. -And in our case, the absence of `name` is an error, as users must have a `name`. +Og i vores tilfælde er fraværet af `name` en fejl, da brugere skal have et `name`. -So let's throw it: +Så lad os kaste den fejl, og håndtere den i `catch`: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // ufuldstændige data try { @@ -317,55 +317,55 @@ try { if (!user.name) { *!* - throw new SyntaxError("Incomplete data: no name"); // (*) + throw new SyntaxError("Ufuldstændige data: name mangler"); // (*) */!* } alert( user.name ); } catch (err) { - alert( "JSON Error: " + err.message ); // JSON Error: Incomplete data: no name + alert( "JSON Error: " + err.message ); // JSON Error: Ufuldstændige data: name mangler } ``` -In the line `(*)`, the `throw` operator generates a `SyntaxError` with the given `message`, the same way as JavaScript would generate it itself. The execution of `try` immediately stops and the control flow jumps into `catch`. +I linjen med `(*)`, genererer `throw` operatoren en `SyntaxError` med den angivne `message`, på samme måde som JavaScript ville generere det selv. Afviklingen af `try` stopper med det samme og kontrollen af flower overgår til `catch`. -Now `catch` became a single place for all error handling: both for `JSON.parse` and other cases. +Nu bliver `catch` det eneste sted for al fejlhåndtering: både for `JSON.parse` og for andre scenarier. ## Rethrowing -In the example above we use `try...catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just this "incorrect data" thing. +I eksemplet ovenfor bruger vi `try...catch` til at håndtere forkert data i JSON filen. Men er det muligt at *en anden uventet fejl* opstår inden for `try {...}` blokken? Som en programmeringsfejl (variabel er ikke defineret) eller noget andet, ikke bare denne "forkerte data" ting. -For example: +For eksempel: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // ufuldstændige data try { - user = JSON.parse(json); // <-- forgot to put "let" before user + user = JSON.parse(json); // <-- glemte at putte "let" foran user // ... } catch (err) { - alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined - // (no JSON Error actually) + alert("JSON Fejl: " + err); // JSON Fejl: ReferenceError: user is not defined + // (faktisk ikke en JSON fejl) } ``` -Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a bug may be discovered that leads to terrible hacks. +Selvfølgelig, alt er muligt! Programmører laver fejl. Selv i open-source værktøjer der er brugt af millioner i årtier -- pludselig kan en fejl blive opdaget, der fører til frygtelige hacks. -In our case, `try...catch` is placed to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug. +I vores tilfælde, `try...catch` er placeret for at fange "forkerte data" fejl. Men selve konstrulktionen dikterer at `catch` får *alle* fejl fra `try`. Her får det en uventet fejl, men viser stadig den samme `"JSON Error"` besked. Det er forkert og gør også koden sværere at debugge. -To avoid such problems, we can employ the "rethrowing" technique. The rule is simple: +For at undgå sådanne problemer, kan vi bruge "rethrowing" teknikken. Reglen er simpel: -**Catch should only process errors that it knows and "rethrow" all others.** +**Catch skal kun behandle fejl, den kender, og "rethrow" alle andre.** -The "rethrowing" technique can be explained in more detail as: +Teknikken "rethrowing" kan forklares lidt mere detaljeret som: -1. Catch gets all errors. -2. In the `catch (err) {...}` block we analyze the error object `err`. -3. If we don't know how to handle it, we do `throw err`. +1. Opfang alle fejl. +2. I blokken `catch (err) {...}` analyserer vi error objektet. +3. Hvis vi ikke ved, hvordan vi skal håndtere den, kaster vi den med `throw err`. -Usually, we can check the error type using the `instanceof` operator: +Normalt kan vi tjekke fejltypen ved hjælp af `instanceof` operatoren: ```js run try { @@ -374,27 +374,27 @@ try { *!* if (err instanceof ReferenceError) { */!* - alert('ReferenceError'); // "ReferenceError" for accessing an undefined variable + alert('ReferenceError'); // "ReferenceError" for at tilgå en variabel der er undefineret } } ``` -We can also get the error class name from `err.name` property. All native errors have it. Another option is to read `err.constructor.name`. +Vi kan også få fejlens navn fra `err.name` egenskaben. Alle indbyggede fejl har den. En anden option er at læse `err.constructor.name`. -In the code below, we use rethrowing so that `catch` only handles `SyntaxError`: +I koden nedenfor, vi bruger rethrowing så `catch` kun håndterer `SyntaxError`: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // ufuldstændige data try { let user = JSON.parse(json); if (!user.name) { - throw new SyntaxError("Incomplete data: no name"); + throw new SyntaxError("Ufuldstændige data: name mangler"); } *!* - blabla(); // unexpected error + blabla(); // uventet fejl */!* alert( user.name ); @@ -403,7 +403,7 @@ try { *!* if (err instanceof SyntaxError) { - alert( "JSON Error: " + err.message ); + alert( "JSON fejl: " + err.message ); } else { throw err; // rethrow (*) } @@ -412,11 +412,11 @@ try { } ``` -The error throwing on line `(*)` from inside `catch` block "falls out" of `try...catch` and can be either caught by an outer `try...catch` construct (if it exists), or it kills the script. +Fejlkastningen på linjen med `(*)` inde i `catch` blokken "falder ud" af `try...catch` og kan enten blive fanget af en ydre `try...catch` construct (hvis den eksisterer), eller også dør scriptet. -So the `catch` block actually handles only errors that it knows how to deal with and "skips" all others. +Så `catch` blokken håndterer faktisk kun fejl, den ved hvordan den skal håndtere, og "dropper" alle andre. -The example below demonstrates how such errors can be caught by one more level of `try...catch`: +Eksemplet nedenfor viser, hvordan sådanne fejl kan blive fanget af et ekstra niveau af `try...catch`: ```js run function readData() { @@ -425,13 +425,13 @@ function readData() { try { // ... *!* - blabla(); // error! + blabla(); // fejl! */!* } catch (err) { // ... if (!(err instanceof SyntaxError)) { *!* - throw err; // rethrow (don't know how to deal with it) + throw err; // rethrow (ved ikke hvordan man skal håndtere det) */!* } } @@ -441,42 +441,42 @@ try { readData(); } catch (err) { *!* - alert( "External catch got: " + err ); // caught it! + alert( "Ydre catch modtog: " + err ); // fangede den! */!* } ``` -Here `readData` only knows how to handle `SyntaxError`, while the outer `try...catch` knows how to handle everything. +Her ved `readData` kun hvordan den skal håndtere `SyntaxError`, mens den ydre `try...catch` ved hvordan den skal håndtere alt. ## try...catch...finally -Wait, that's not all. +vent, der er mere endnu. -The `try...catch` construct may have one more code clause: `finally`. +Konstruktionen `try...catch` har en såkaldt klausul mere, nemlig `finally`. -If it exists, it runs in all cases: +Hvis den eksisterer, kører den i alle tilfælde: -- after `try`, if there were no errors, -- after `catch`, if there were errors. +- efter `try`, hvis der ikke var nogen fejl, +- efter `catch`, hvis der var fejl. -The extended syntax looks like this: +Den udvidede syntaks ser sådan ud: ```js *!*try*/!* { - ... try to execute the code ... + ... prøv at afvikle noget kode ... } *!*catch*/!* (err) { - ... handle errors ... + ... håndter fejl ... } *!*finally*/!* { - ... execute always ... + ... kører altid til sidst ... } ``` -Try running this code: +Prøv at køre denne kode for at se, hvordan det fungerer: ```js run try { alert( 'try' ); - if (confirm('Make an error?')) BAD_CODE(); + if (confirm('Skal der laves en fejl?')) BAD_CODE(); } catch (err) { alert( 'catch' ); } finally { @@ -484,27 +484,27 @@ try { } ``` -The code has two ways of execution: +Koden har to måder at blive afviklet på: -1. If you answer "Yes" to "Make an error?", then `try -> catch -> finally`. -2. If you say "No", then `try -> finally`. +1. Hvis du svarer "Ja" til "Skal der laves en fejl?", så `try -> catch -> finally`. +2. Hvis du svarer "Nej", så `try -> finally`. -The `finally` clause is often used when we start doing something and want to finalize it in any case of outcome. +Klausulen `finally` bruges ofte, når vi starter noget og vil have det afsluttet uanset resultatet. -For instance, we want to measure the time that a Fibonacci numbers function `fib(n)` takes. Naturally, we can start measuring before it runs and finish afterwards. But what if there's an error during the function call? In particular, the implementation of `fib(n)` in the code below returns an error for negative or non-integer numbers. +For eksempel, vi vil måle tiden, det tager at køre en Fibonacci tal funktion `fib(n)`. Naturligvis kan vi starte måling før den kører og afslutte efterfølgende. Men hvad hvis der er en fejl under funktionskaldet? Især implementationen af `fib(n)` i koden nedenfor returnerer en fejl for negative eller ikke-heltalstal. -The `finally` clause is a great place to finish the measurements no matter what. +`finally` klausulen er et godt sted at afslutte målingerne uanset hvad. -Here `finally` guarantees that the time will be measured correctly in both situations -- in case of a successful execution of `fib` and in case of an error in it: +Her garanterer `finally` at tiden vil blive målt korrekt i begge situationer -- i tilfælde af en succesfuld udførelse af `fib` og i tilfælde af en fejl i den: ```js run -let num = +prompt("Enter a positive integer number?", 35) +let num = +prompt("Skriv et positivt heltal?", 35) let diff, result; function fib(n) { if (n < 0 || Math.trunc(n) != n) { - throw new Error("Must not be negative, and also an integer."); + throw new Error("Tallet må ikke være negativt, og det skal være et heltal."); } return n <= 1 ? n : fib(n - 1) + fib(n - 2); } @@ -521,26 +521,26 @@ try { } */!* -alert(result || "error occurred"); +alert(result || "der skete en fejl"); -alert( `execution took ${diff}ms` ); +alert( `udførelsen tog ${diff}ms` ); ``` -You can check by running the code with entering `35` into `prompt` -- it executes normally, `finally` after `try`. And then enter `-1` -- there will be an immediate error, and the execution will take `0ms`. Both measurements are done correctly. +Du kan nu køre koden med at indtaste `35` i `prompt` -- den kører normalt, `finally` efter `try`. Prøv bagefter at indtaste `-1` -- der vil umiddelbart være en fejl, og udførelsen vil tage `0ms`. Begge målinger er udført korrekt. -In other words, the function may finish with `return` or `throw`, that doesn't matter. The `finally` clause executes in both cases. +Med andre ord, funktionen kan slutte med `return` eller `throw`, det spiller ingen rolle. Klausulen `finally` udføres i begge tilfælde. -```smart header="Variables are local inside `try...catch...finally`" -Please note that `result` and `diff` variables in the code above are declared *before* `try...catch`. +```smart header="Variable er lokale inde i `try...catch...finally`" +Bemærk at `result` og `diff` variablene i koden ovenfor er deklareret *før* `try...catch`. -Otherwise, if we declared `let` in `try` block, it would only be visible inside of it. +Ellers, hvis vi deklarerede `let` i `try` blokken, ville den kun være synlig inden for den. ``` -````smart header="`finally` and `return`" -The `finally` clause works for *any* exit from `try...catch`. That includes an explicit `return`. +````smart header="`finally` og `return`" +Klausulen `finally` virker for *alle* udgange fra `try...catch`. Det indbefatter også en eksplicit `return`. -In the example below, there's a `return` in `try`. In this case, `finally` is executed just before the control returns to the outer code. +I eksemplet nedenfor, er der en `return` i `try`. I dette tilfælde, udføres `finally` lige før kontrol returnerer til den ydre kode. ```js run function func() { @@ -559,40 +559,40 @@ function func() { } } -alert( func() ); // first works alert from finally, and then this one +alert( func() ); // først kommer alert fra finally, og derefter kommer denne der kalder func() ``` ```` ````smart header="`try...finally`" -The `try...finally` construct, without `catch` clause, is also useful. We apply it when we don't want to handle errors here (let them fall through), but want to be sure that processes that we started are finalized. +Konstruktionen `try...finally` uden klausulen `catch` kan også være brugbar. Den bruger vi, hvis vi ikke vil håndtere fejl her (lad dem falde gennem), men vil være sikker på, at processer, vi har startet, bliver afsluttet. ```js function func() { - // start doing something that needs completion (like measurements) + // start noget der skal afsluttes (som målinger, eller en databaseforbindelse, eller noget andet) try { // ... } finally { - // complete that thing even if all dies + // førdiggør eller ryd op lige meget om det fejler eller ej } } ``` -In the code above, an error inside `try` always falls out, because there's no `catch`. But `finally` works before the execution flow leaves the function. +I koden ovenfor vil en fejl inde `try` altid falde ud, fordi der ikke er en `catch`. Men `finally` virker før afviklingsflowet forlader funktionen. ```` ## Global catch -```warn header="Environment-specific" -The information from this section is not a part of the core JavaScript. +```warn header="Miljøspecifikt" +Informationen i denne sektion er ikke en del af selve JavaScript sproget. ``` -Let's imagine we've got a fatal error outside of `try...catch`, and the script died. Like a programming error or some other terrible thing. +Lad os forestille os, at vi får en fatal fejl uden for `try...catch`, og scriptet dør. Som en programmeringsfejl eller noget andet skrækkeligt. -Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages), etc. +Er der en måde at reagere på sådanne tilfælde? Vi vil måske logge fejlen, vise noget til brugeren (normalt ser de ikke fejlbeskeder), etc. -There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to the special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error. +Der er ingen i specifikationen, men miljøer ofte leverer det, fordi det er virkelig nyttigt. For eksempel har Node.js [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for det. Og i browseren kan vi tildele en funktion til den specielle [window.onerror](mdn:api/GlobalEventHandlers/onerror) egenskab, som vil køre i tilfælde af en ikke-fanget fejl. -The syntax: +Syntaksen er: ```js window.onerror = function(message, url, line, col, error) { @@ -601,18 +601,18 @@ window.onerror = function(message, url, line, col, error) { ``` `message` -: Error message. +: Fejlmeddelelsen. `url` -: URL of the script where error happened. +: URL for det script hvor fejlen opstod. `line`, `col` -: Line and column numbers where error happened. +: Linje og kolonne numre hvor fejlen opstod. `error` -: Error object. +: Error objekt. -For instance: +For eksempel, denne kode har en fejl, og den vil blive fanget af `window.onerror`: ```html run untrusted refresh height=1 ``` -The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers. - -There are also web-services that provide error-logging for such cases, like or . +Rollen for den globale håndtering med `window.onerror` er normalt ikke for at genskabe scripteksekveringen -- det er sandsynligvis umuligt i tilfælde af programmeringsfejl, men for at sende fejlmeddelelsen til udviklerne. -They work like this: +Der er også web-tjenester, der leverer fejllogning for sådanne tilfælde, som eller . -1. We register at the service and get a piece of JS (or a script URL) from them to insert on pages. -2. That JS script sets a custom `window.onerror` function. -3. When an error occurs, it sends a network request about it to the service. -4. We can log in to the service web interface and see errors. +De virker sådan her: +1.Vi registrerer os hos services og får et stykke JS-kode (eller en URL til et script) fra dem til at indsætte på sider. +2. Dette JS-script sætter en brugerdefineret `window.onerror` funktion. +3. Når der sker en fejl, sender den en network request omkring det til tjenesten. +4. Vi kan så logge ind på tjenestens webinterface og se fejl. -## Summary +## Opsummering -The `try...catch` construct allows to handle runtime errors. It literally allows to "try" running the code and "catch" errors that may occur in it. +Konstruktionen `try...catch` tillade os at håndtere runtime-fejl. Det tillader os bogstaveligt talt at "prøve" at køre koden og "fange" fejl, der kan opstå i den. -The syntax is: +Syntaksen er: ```js try { - // run this code + // kør denne kode } catch (err) { - // if an error happened, then jump here - // err is the error object + // hvis der sker en fejl, så hop hertil + // err er et objekt der indeholder fejlinformationen } finally { - // do in any case after try/catch + // gør dette uanset om der sker en fejl eller ej } ``` -There may be no `catch` section or no `finally`, so shorter constructs `try...catch` and `try...finally` are also valid. +Der behøver ikke at være en `catch` klausul eller en `finally` klausul, så kortere konstruktioner `try...catch` og `try...finally` er også gyldige. -Error objects have following properties: +Error objekter har følgende egenskaber: -- `message` -- the human-readable error message. -- `name` -- the string with error name (error constructor name). -- `stack` (non-standard, but well-supported) -- the stack at the moment of error creation. +- `message` -- fejlmeddelelsen. +- `name` -- strengen med fejlnavnet (konstruktoren navn). +- `stack` (ikke-standard, men ret udbredt) -- stakken ved øjeblikket for fejl oprettelsen. -If an error object is not needed, we can omit it by using `catch {` instead of `catch (err) {`. +Hvis vi ikke behøver et error object, kan du udelade det ved at bruge `catch {` i stedet for `catch (err) {`. -We can also generate our own errors using the `throw` operator. Technically, the argument of `throw` can be anything, but usually it's an error object inheriting from the built-in `Error` class. More on extending errors in the next chapter. +Vi kan også generere vores egne fejl ved hjælp af `throw` operatoren. Teknisk set kan argumentet for `throw` være hvad som helst, men normalt er det et error object, der nedarver fra den indbyggede `Error` klasse. Mere om at udvide fejl i næste kapitel. -*Rethrowing* is a very important pattern of error handling: a `catch` block usually expects and knows how to handle the particular error type, so it should rethrow errors it doesn't know. +*Rethrowing* er en meget vigtig mønster for fejlhåndtering: en `catch` blok forventes typisk at vide, hvordan den skal håndtere den specifikke fejltype, så den bør kaste fejlen igen, hvis den ikke kender til den. -Even if we don't have `try...catch`, most environments allow us to setup a "global" error handler to catch errors that "fall out". In-browser, that's `window.onerror`. +Selv hvis vi ikke har `try...catch`, tillader de fleste miljøer os at opsætte en "global" fejlhåndtering for at fange fejl, der "falder ud". I browseren er det `window.onerror`. diff --git a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg index 2c0d7134..336936c3 100644 --- a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg +++ b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg @@ -1 +1,91 @@ -BeginNo ErrorsAn error occured in the codeIgnore catch blockIgnore the rest of tryExecute catch blocktry { }// code... \ No newline at end of file + + + + + + + + + + + + Start + + + + + + + + + + + + + Ingen fejl + + + + + + En fejl skete i koden + + + + + + + Ignorer catch blok + + + Ignorer resten af try + + + Eksekver catch blokken + + + try { + + } + + + // code... + + + + \ No newline at end of file From e284bdb9ed9a97e6e7324614955aeb72fdc04d65 Mon Sep 17 00:00:00 2001 From: ockley Date: Fri, 20 Mar 2026 16:54:05 +0100 Subject: [PATCH 13/13] ovesat til dansk --- .../1-format-error/solution.md | 4 +- .../2-custom-errors/1-format-error/task.md | 14 +- .../2-custom-errors/article.md | 148 +++++++++--------- 1-js/10-error-handling/index.md | 2 +- 4 files changed, 84 insertions(+), 84 deletions(-) diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md index 754e68f9..57109386 100644 --- a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md +++ b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md @@ -6,9 +6,9 @@ class FormatError extends SyntaxError { } } -let err = new FormatError("formatting error"); +let err = new FormatError("formattingsfejl"); -alert( err.message ); // formatting error +alert( err.message ); // formatteringsfejl alert( err.name ); // FormatError alert( err.stack ); // stack diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md index 2c8e910f..8886e2cb 100644 --- a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md +++ b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md @@ -2,21 +2,21 @@ importance: 5 --- -# Inherit from SyntaxError +# Nedarv fra SyntaxError -Create a class `FormatError` that inherits from the built-in `SyntaxError` class. +Opret en klasse `FormatError` som nedarver fra den indbyggede `SyntaxError`-klasse. -It should support `message`, `name` and `stack` properties. +Den bør understøtte `message`, `name` og `stack` egenskaber. -Usage example: +Brugseksempel: ```js -let err = new FormatError("formatting error"); +let err = new FormatError("formatteringsfejl"); -alert( err.message ); // formatting error +alert( err.message ); // formatteringsfejl alert( err.name ); // FormatError alert( err.stack ); // stack alert( err instanceof FormatError ); // true -alert( err instanceof SyntaxError ); // true (because inherits from SyntaxError) +alert( err instanceof SyntaxError ); // true (fordi den nedarver fra SyntaxError) ``` diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index d28b0743..40531977 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -1,42 +1,42 @@ -# Custom errors, extending Error +# Brugerdefinerede fejl, udvidelse af Error -When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on. +Når vi udvikler noget, har vi ofte brug for egne fejlklasser til at reflektere specifikke ting, der kan gå galt i vores opgaver. For fejl i netværksoperationer kan vi have brug for `HttpError`, for databaseoperationer `DbError`, for søgeoperationer `NotFoundError` og så videre. -Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have a `statusCode` property with a value like `404` or `403` or `500`. +Vores fejl bør understøtte grundlæggende fejl egenskaber som `message`, `name` og meget gerne `stack`. Men de kan også have andre egenskaber af deres egen type, f.eks. `HttpError` objekter kan have en `statusCode` egenskab med en værdi som `404` eller `403` eller `500`. -JavaScript allows to use `throw` with any argument, so technically our custom error classes don't need to inherit from `Error`. But if we inherit, then it becomes possible to use `obj instanceof Error` to identify error objects. So it's better to inherit from it. +JavaScript tillader at bruge `throw` med ethvert argument, så teknisk set behøver vores custom error klasser ikke at arve fra `Error`. Men hvis vi arver, så bliver det muligt at bruge `obj instanceof Error` til at identificere fejl objekter. Så det er bedre at arve fra den. -As the application grows, our own errors naturally form a hierarchy. For instance, `HttpTimeoutError` may inherit from `HttpError`, and so on. +Efterhånden som applikationen vokser, vil vores egne fejl naturligvis danne en hierarki. For eksempel kan `HttpTimeoutError` arve fra `HttpError`, og så videre. -## Extending Error +## Udvidelse af Error -As an example, let's consider a function `readUser(json)` that should read JSON with user data. +Som et eksempel, lad os overveje en funktion `readUser(json)` som skal læse JSON med brugerdata. -Here's an example of how a valid `json` may look: +Her er et eksempel på, hvordan et gyldigt `json` kan se ud: ```js let json = `{ "name": "John", "age": 30 }`; ``` -Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users. +Internt bruger vi `JSON.parse`. Hvis den modtager fejlformateret `json`, så kaster den `SyntaxError`. Men selv hvis `json` er syntaktisk korrekt, betyder det jo ikke nødvendigvis, at det er en gyldig bruger? Det kan mangle de nødvendige data. For eksempel kan det ikke have `name` og `age` egenskaber, som er afgørende for vores brugere. -Our function `readUser(json)` will not only read JSON, but check ("validate") the data. If there are no required fields, or the format is wrong, then that's an error. And that's not a `SyntaxError`, because the data is syntactically correct, but another kind of error. We'll call it `ValidationError` and create a class for it. An error of that kind should also carry the information about the offending field. +Vores funktion `readUser(json)` vil ikke kun læse JSON, men også tjekke ("validere") dataene. Hvis der mangler at blive udfyldt påkrævede felter, eller det er formatet er forkert, så er det en fejl. Og det er ikke en `SyntaxError`, fordi dataene er syntaktisk korrekte, men en anden type af fejl. Vi vil kalde det `ValidationError` og oprette en klasse til det. En fejl af denne type bør også bære informationen om det fejlbehagende felt. -Our `ValidationError` class should inherit from the `Error` class. +Vores `ValidationError` klasse bør arve fra `Error` klassen. -The `Error` class is built-in, but here's its approximate code so we can understand what we're extending: +Klassen `Error` er indbygget, men her er dens omtrentlige kode, så vi kan forstå, hvad vi udvider: ```js -// The "pseudocode" for the built-in Error class defined by JavaScript itself +// "pseudocode" for den indbyggede Error klasse defineret af JavaScript selv class Error { constructor(message) { this.message = message; - this.name = "Error"; // (different names for different built-in error classes) - this.stack = ; // non-standard, but most environments support it + this.name = "Error"; // (forskellige navne for forskellige indbyggede fejltyper) + this.stack = ; // ikke-standard, men de fleste miljøer understøtter det } } ``` -Now let's inherit `ValidationError` from it and try it in action: +Lad nu `ValidationError` udvide denne `Error` og prøve at bruge den: ```js run *!* @@ -49,23 +49,23 @@ class ValidationError extends Error { } function test() { - throw new ValidationError("Whoops!"); + throw new ValidationError("Ups!"); } try { test(); } catch(err) { - alert(err.message); // Whoops! + alert(err.message); // Ups! alert(err.name); // ValidationError - alert(err.stack); // a list of nested calls with line numbers for each + alert(err.stack); // en liste af indlejrede kald med linjenumre for hvor fejlen opstod } ``` -Please note: in the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property. +Bemærk: i linjen `(1)` kalder vi 'parent constructor'. JavaScript kræver at vi kalder `super` i 'child constructor', så det er obligatorisk. Forældrekonstruktøren sætter `message` egenskaben. -The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value. +Forældrekonstruktøren sætter også `name` egenskaben til `"Error"`, så i linjen `(2)` nulstiller vi den til den rigtige værdi. -Let's try to use it in `readUser(json)`: +Lad os prøve at bruge den i `readUser(json)`: ```js run class ValidationError extends Error { @@ -80,52 +80,52 @@ function readUser(json) { let user = JSON.parse(json); if (!user.age) { - throw new ValidationError("No field: age"); + throw new ValidationError("Mangler feltet: age"); } if (!user.name) { - throw new ValidationError("No field: name"); + throw new ValidationError("Mangler feltet: name"); } return user; } -// Working example with try..catch +// Eksempel med try..catch try { let user = readUser('{ "age": 25 }'); } catch (err) { if (err instanceof ValidationError) { *!* - alert("Invalid data: " + err.message); // Invalid data: No field: name + alert("Ugyldige data: " + err.message); // Ugyldige data: Mangler feltet: name */!* } else if (err instanceof SyntaxError) { // (*) - alert("JSON Syntax Error: " + err.message); + alert("JSON Syntaksfejl: " + err.message); } else { - throw err; // unknown error, rethrow it (**) + throw err; // ukendt fejl, kast den videre (**) } } ``` -The `try..catch` block in the code above handles both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse`. +Blokken `try..catch` i koden ovenfor åndterer både vores `ValidationError` og den indbyggede `SyntaxError` fra `JSON.parse`. -Please take a look at how we use `instanceof` to check for the specific error type in the line `(*)`. +Se hvordan vi gør brug af `instanceof` til at tjekke for den specifikke fejltype i linjen `(*)`. -We could also look at `err.name`, like this: +Vi kan også kigge på `err.name`, sådan her: ```js // ... -// instead of (err instanceof SyntaxError) +// i stedet for (err instanceof SyntaxError) } else if (err.name == "SyntaxError") { // (*) // ... ``` -The `instanceof` version is much better, because in the future we are going to extend `ValidationError`, make subtypes of it, like `PropertyRequiredError`. And `instanceof` check will continue to work for new inheriting classes. So that's future-proof. +`instanceof` versionen er meget bedre, fordi vi i fremtiden måske vil udvide `ValidationError`, lave undertyper af den i stil med `PropertyRequiredError`. Et tjek med `instanceof` vil stadig virke for nedarvede klasser. På den måde er det fremtidssikret. -Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (caused by a typo in the code or other unknown reasons) should fall through. +Det er også vigtigt, at hvis `catch` møder en ukendt fejl, så kaster den den videre i linjen `(**)`. Denne `catch` blok ved kun hvordan vi håndterer validerings- og syntaksfejl. Alt andet (sket ved en fejl i koden eller andre ukendte årsager) skal falde igennem. -## Further inheritance +## Videre nedarvning -The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age` instead of a number). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing. +Klassen `ValidationError` er meget generisk - mange ting kan gå galt. Egenskaben kan mangle eller den kan være i et forkert format (som en strengværdi for `age` i stedet for et tal). Lad os lave en mere konkret klasse `PropertyRequiredError`, præcist til at håndtere manglende egenskaber. Den vil bære yderligere information om den egenskab, der mangler. ```js run class ValidationError extends Error { @@ -138,7 +138,7 @@ class ValidationError extends Error { *!* class PropertyRequiredError extends ValidationError { constructor(property) { - super("No property: " + property); + super("Mangler egenskab: " + property); this.name = "PropertyRequiredError"; this.property = property; } @@ -159,32 +159,32 @@ function readUser(json) { return user; } -// Working example with try..catch +// Eksempel med try..catch try { let user = readUser('{ "age": 25 }'); } catch (err) { if (err instanceof ValidationError) { *!* - alert("Invalid data: " + err.message); // Invalid data: No property: name + alert("Ugyldige data: " + err.message); // Ugyldige data: Mangler egenskab: name alert(err.name); // PropertyRequiredError alert(err.property); // name */!* } else if (err instanceof SyntaxError) { - alert("JSON Syntax Error: " + err.message); + alert("JSON Syntaksfejl: " + err.message); } else { - throw err; // unknown error, rethrow it + throw err; // ukendt fejl, kast den videre } } ``` -The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor. +Den nye klasse `PropertyRequiredError` er nem at bruge: vi behøver bare at videregive egenskabens navn: `new PropertyRequiredError(property)`. Den læsevenlige `message` bliver skabt i konstruktøren. -Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all our custom errors from it. +Bemærk at `this.name` in `PropertyRequiredError` constructor er igen tildelt manuelt. Det kan blive en smule besværligt -- at tildele `this.name = ` i hver custom error klasse. Vi kan undgå det ved at lave vores egen "basic error" klasse, der tildele `this.name = this.constructor.name`. Og så nedarve alle vores custom errors fra den. -Let's call it `MyError`. +Lad os kalde det `MyError`. -Here's the code with `MyError` and other custom error classes, simplified: +Her er koden med `MyError` og andre custom error klasser, forenklet: ```js run class MyError extends Error { @@ -200,56 +200,56 @@ class ValidationError extends MyError { } class PropertyRequiredError extends ValidationError { constructor(property) { - super("No property: " + property); + super("Ingen egenskab: " + property); this.property = property; } } -// name is correct +// name er korrekt indstillet af MyError alert( new PropertyRequiredError("field").name ); // PropertyRequiredError ``` -Now custom errors are much shorter, especially `ValidationError`, as we got rid of the `"this.name = ..."` line in the constructor. +Nu er brugerdefinerede fejl meget kortere, især `ValidationError`, da vi har fjernet linjen `"this.name = ..."` i constructor. -## Wrapping exceptions +## Indpakning af undtagelser (expeptions) -The purpose of the function `readUser` in the code above is "to read the user data". There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors. +Meningen med funktionen `readUser` i koden ovenfor er "at læse brugerdata". Der kan opstå forskellige slags fejl i den proces. Som det er nu har vi `SyntaxError` og `ValidationError`, men i en fremtidig `readUser` funktion kan det vokse og måske generere andre typer fejl. -The code which calls `readUser` should handle these errors. Right now it uses multiple `if`s in the `catch` block, that check the class and handle known errors and rethrow the unknown ones. +Koden der kalder `readUser` bør håndtere disse fejl. Lige nu bruger den flere `if` inde i `catch` blokken, der tjekker klassen og håndterer kendte fejl og kaster de ukendte videre. -The scheme is like this: +Skemaet er sådan her: ```js try { ... - readUser() // the potential error source + readUser() // den potentielle fejlkilde ... } catch (err) { if (err instanceof ValidationError) { - // handle validation errors + // håndter valideringsfejl } else if (err instanceof SyntaxError) { - // handle syntax errors + // håndter syntaksfejl } else { - throw err; // unknown error, rethrow it + throw err; // ukendt fejl, kast den videre } } ``` -In the code above we can see two types of errors, but there can be more. +I koden ovenfor kan vi se to typer af fejl, men der kan være flere. -If the `readUser` function generates several kinds of errors, then we should ask ourselves: do we really want to check for all error types one-by-one every time? +Hvis `readUser`-funktionen genererer flere typer af fejl, så bør vi spørge os selv: vil vi virkelig have lyst til at skulle tjekke for alle fejltyper - en efter en - hver gang? -Often the answer is "No": we'd like to be "one level above all that". We just want to know if there was a "data reading error" -- why exactly it happened is often irrelevant (the error message describes it). Or, even better, we'd like to have a way to get the error details, but only if we need to. +Ofte er svaret "Nej": vi vil gerne være "et niveau over alt det". Vi vil bare have at vide om der var en "data læsningsfejl" -- hvorfor det præcist skete er ofte irrelevant (fejlmeddelelsen beskriver det). Eller, endnu bedre, vi vil gerne have en måde at få detaljerne om fejlen på ... men kun hvis vi har brug for dem. -The technique that we describe here is called "wrapping exceptions". +Den teknik vi beskriver her kaldes "wrapping exceptions". -1. We'll make a new class `ReadError` to represent a generic "data reading" error. -2. The function `readUser` will catch data reading errors that occur inside it, such as `ValidationError` and `SyntaxError`, and generate a `ReadError` instead. -3. The `ReadError` object will keep the reference to the original error in its `cause` property. +1. Vi laver en ny klasse `ReadError` til at repræsentere en generisk "data læsning" fejl. +2. Funktionen `readUser` vil fange data læsningsfejl, der opstår inden for den, såsom `ValidationError` og `SyntaxError`, og generere en `ReadError` i stedet. +3. `ReadError`-objektet vil gemme referencen til den originale fejl i sin `cause`-egenskab. -Then the code that calls `readUser` will only have to check for `ReadError`, not for every kind of data reading errors. And if it needs more details of an error, it can check its `cause` property. +Således vil koden, der kalder `readUser`, kun behøve at tjekke for `ReadError`, ikke for hver enkelt type data læsningsfejl. Og hvis den har brug for flere detaljer om en fejl, kan den tjekke dens `cause`-egenskab. -Here's the code that defines `ReadError` and demonstrates its use in `readUser` and `try..catch`: +Her er koden, der definerer `ReadError` og demonstrerer dens brug i `readUser` og `try..catch`: ```js run class ReadError extends Error { @@ -281,7 +281,7 @@ function readUser(json) { } catch (err) { *!* if (err instanceof SyntaxError) { - throw new ReadError("Syntax Error", err); + throw new ReadError("Syntaksfejl", err); } else { throw err; } @@ -293,7 +293,7 @@ function readUser(json) { } catch (err) { *!* if (err instanceof ValidationError) { - throw new ReadError("Validation Error", err); + throw new ReadError("Valideringsfejl", err); } else { throw err; } @@ -317,14 +317,14 @@ try { } ``` -In the code above, `readUser` works exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual). +I koden ovenfor fungerer `readUser` præcis som beskrevet -- fanger syntaks- og valideringsfejl og kaster `ReadError`-fejl i stedet (ukendte fejl kastes videre som normalt). -So the outer code checks `instanceof ReadError` and that's it. No need to list all possible error types. +Så den ydre kode tjekker `instanceof ReadError` og det er det. Ingen grund til at gennemgå alle mulige fejltyper. -The approach is called "wrapping exceptions", because we take "low level" exceptions and "wrap" them into `ReadError` that is more abstract. It is widely used in object-oriented programming. +Den kaldes "wrapping exceptions", fordi den tager "low level" undtagelser og "pakker" dem ind i `ReadError` der er mere abstrakt. Denne teknik er meget brugt i objektorienteret programmering. -## Summary +## Opsummering -- We can inherit from `Error` and other built-in error classes normally. We just need to take care of the `name` property and don't forget to call `super`. -- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from a 3rd-party library and there's no easy way to get its class. Then `name` property can be used for such checks. -- Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required. +- Vi kan nedarve fra `Error` og andre indbyggede fejltyper på normal vis. Vi skal bare tage huske på `name`-egenskaben og ikke glemme at kalde `super`. +- Vi kan bruge `instanceof` til at tjekke for bestemte fejl. Det virker også med nedarvning. Men nogle gange har vi et fejlobjekt, der kommer fra en 3.parts bibliotek, hvor der måske ikke er en enkel måde at få dens klasse. Her kan `name`-egenskaben bruges til sådanne tjek. +- Wrapping exceptions er en almindelig teknik: en funktion håndterer lav-niveau undtagelser og opretter højere-niveau fejl i stedet for forskellige lav-niveau fejl. Lav-niveau undtagelser bliver nogle gange til egenskaber på det objekt, som `err.cause` i eksemplerne ovenfor, men det er ikke strengt nødvendigt. diff --git a/1-js/10-error-handling/index.md b/1-js/10-error-handling/index.md index face61c6..aa2db89c 100644 --- a/1-js/10-error-handling/index.md +++ b/1-js/10-error-handling/index.md @@ -1 +1 @@ -# Error handling +# Håndtering af fejl