Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Yeah, looks strange indeed.
Ja, det er lidt mærkeligt.

But `instanceof` does not care about the function, but rather about its `prototype`, that it matches against the prototype chain.
Men `instanceof` bryder sig ikke om funktionen, men snarere om dens `prototype`, som den matcher mod prototype-kæden.

And here `a.__proto__ == B.prototype`, so `instanceof` returns `true`.
Og her er `a.__proto__ == B.prototype`, `instanceof` returnerer `true`.

So, by the logic of `instanceof`, the `prototype` actually defines the type, not the constructor function.
Så, hvis man følger logikken for `instanceof`, så definerer `prototype` faktisk typen, ikke constructor-funktionen.
4 changes: 2 additions & 2 deletions 1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ importance: 5

---

# Strange instanceof
# Underlig instanceof

In the code below, why does `instanceof` return `true`? We can easily see that `a` is not created by `B()`.
Se på koden nedenfor. Hvorfor returnerer `instanceof` værdien `true`? Vi kan tydelig se, at `a` ikke er oprettet af `B()`.

```js run
function A() {}
Expand Down
116 changes: 58 additions & 58 deletions 1-js/09-classes/06-instanceof/article.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,62 @@
# Class checking: "instanceof"
# Tjek en klasse: "instanceof"

The `instanceof` operator allows to check whether an object belongs to a certain class. It also takes inheritance into account.
Operatoren `instanceof` tillader at tjekke om et objekt tilhører en bestemt klasse. Den tager også arv i betragtning.

Such a check may be necessary in many cases. For example, it can be used for building a *polymorphic* function, the one that treats arguments differently depending on their type.
Sådan en tjek kan være nødvendig i mange tilfælde. For eksempel kan den bruges til at bygge en *polymorfisk* funktion, som behandler argumenter forskelligt afhængigt af deres type.

## The instanceof operator [#ref-instanceof]
## instanceof operatoren [#ref-instanceof]

The syntax is:
Syntaksen er:
```js
obj instanceof Class
```

It returns `true` if `obj` belongs to the `Class` or a class inheriting from it.
Den returnerer `true` hvis `obj` tilhører `Class` eller en klasse som arver fra den.

For instance:
For eksempel:

```js run
class Rabbit {}
let rabbit = new Rabbit();

// is it an object of Rabbit class?
// er det et objekt der er skabt af Rabbit klassen?
*!*
alert( rabbit instanceof Rabbit ); // true
*/!*
```

It also works with constructor functions:
Det virker også med constructor funktioner:

```js run
*!*
// instead of class
// istedet for class
function Rabbit() {}
*/!*

alert( new Rabbit() instanceof Rabbit ); // true
```

...And with built-in classes like `Array`:
... og med indbyggede klasser som `Array`:

```js run
let arr = [1, 2, 3];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true
```

Please note that `arr` also belongs to the `Object` class. That's because `Array` prototypically inherits from `Object`.
Bemærk at `arr` også tilhører `Object`-klassen. Det er fordi `Array` prototypisk arver fra `Object`.

Normally, `instanceof` examines the prototype chain for the check. We can also set a custom logic in the static method `Symbol.hasInstance`.
Normalt undersøger `instanceof` prototype-kæden for tjekket. Vi kan også sætte en tilpasset logik i den statiske metode `Symbol.hasInstance`.

The algorithm of `obj instanceof Class` works roughly as follows:
Algoritmen for `obj instanceof Class` fungerer cirka sådan:

1. If there's a static method `Symbol.hasInstance`, then just call it: `Class[Symbol.hasInstance](obj)`. It should return either `true` or `false`, and we're done. That's how we can customize the behavior of `instanceof`.
1. Hvis der er en statisk metode `Symbol.hasInstance`, så kald den: `Class[Symbol.hasInstance](obj)`. Den skal returnere enten `true` eller `false`, og så er vi færdige. På den måde kan vi tilpasse adfærden for `instanceof`.

For example:
For eksempel:

```js run
// set up instanceof check that assumes that
// anything with canEat property is an animal
// sæt et instanceof tjek der regner med
// at alt med en canEat egenskab er et dyr
class Animal {
static [Symbol.hasInstance](obj) {
if (obj.canEat) return true;
Expand All @@ -65,24 +65,24 @@ The algorithm of `obj instanceof Class` works roughly as follows:

let obj = { canEat: true };

alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called
alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) kaldes
```

2. Most classes do not have `Symbol.hasInstance`. In that case, the standard logic is used: `obj instanceof Class` checks whether `Class.prototype` is equal to one of the prototypes in the `obj` prototype chain.
2. De fleste klasser har ikke `Symbol.hasInstance`. I det tilfælde bruges standardlogikken: `obj instanceof Class` tjekker om `Class.prototype` er lig med en af prototyperne i `obj`'s prototypekæde.

In other words, compare one after another:
Med andre ord, sammenlign en efter en:
```js
obj.__proto__ === Class.prototype?
obj.__proto__.__proto__ === Class.prototype?
obj.__proto__.__proto__.__proto__ === Class.prototype?
...
// if any answer is true, return true
// otherwise, if we reached the end of the chain, return false
// hvis en af svarene er true, returner true
// ellers, hvis vi nåede enden af kæden, returner false
```

In the example above `rabbit.__proto__ === Rabbit.prototype`, so that gives the answer immediately.
I eksemplet ovenfor `rabbit.__proto__ === Rabbit.prototype`, så det giver svaret øjeblikkeligt.

In the case of an inheritance, the match will be at the second step:
I tilfældet af nedarvning vil matchningen være på det andet trin:

```js run
class Animal {}
Expand All @@ -99,70 +99,70 @@ The algorithm of `obj instanceof Class` works roughly as follows:
*/!*
```

Here's the illustration of what `rabbit instanceof Animal` compares with `Animal.prototype`:
Her er en illustration af hvad`rabbit instanceof Animal` sammenligner med `Animal.prototype`:

![](instanceof.svg)

By the way, there's also a method [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), that returns `true` if `objA` is somewhere in the chain of prototypes for `objB`. So the test of `obj instanceof Class` can be rephrased as `Class.prototype.isPrototypeOf(obj)`.
Forresten er der også en metode kaldet [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), der returnerer `true` hvis `objA` er et eller andet sted i kæden af prototyper for `objB`. Så testen af `obj instanceof Class` kan omformuleres som `Class.prototype.isPrototypeOf(obj)`.

It's funny, but the `Class` constructor itself does not participate in the check! Only the chain of prototypes and `Class.prototype` matters.
Det er lidt morsomt, men `Class` konstruktøren deltager ikke selve i checket! Det er kun kæden af prototyper og `Class.prototype` der har betydning.

That can lead to interesting consequences when a `prototype` property is changed after the object is created.
Dette kan føre til interessante konsekvenser når en `prototype` egenskab ændres efter objektet er oprettet.

Like here:
Lige som her:

```js run
function Rabbit() {}
let rabbit = new Rabbit();

// changed the prototype
// ændret prototypen
Rabbit.prototype = {};

// ...not a rabbit any more!
// ...ikke en "Rabbit" mere!
*!*
alert( rabbit instanceof Rabbit ); // false
*/!*
```

## Bonus: Object.prototype.toString for the type
## Bonus: Object.prototype.toString for typen

We already know that plain objects are converted to string as `[object Object]`:
Vi ved allerede at rene objekter er konverteret til streng som `[object Object]`:

```js run
let obj = {};

alert(obj); // [object Object]
alert(obj.toString()); // the same
alert(obj.toString()); // det samme: [object Object]
```

That's their implementation of `toString`. But there's a hidden feature that makes `toString` actually much more powerful than that. We can use it as an extended `typeof` and an alternative for `instanceof`.
Det er deres implementering af `toString`. Men der er en skjult feature der faktisk gør `toString` mere kraftfuld end det. Vi kan bruge den som en udvidet `typeof` og et alternativ til `instanceof`.

Sounds strange? Indeed. Let's demystify.
Lyder det underligt? Ja, det gør! Men lad os afmystificere det.

By [specification](https://tc39.github.io/ecma262/#sec-object.prototype.tostring), the built-in `toString` can be extracted from the object and executed in the context of any other value. And its result depends on that value.
I [specifikationen](https://tc39.github.io/ecma262/#sec-object.prototype.tostring) står der, at den indbyggede `toString` kan trækkes fra objektet og udføres i konteksten af en anden værdi. Og dens resultat afhænger af den værdi.

- For a number, it will be `[object Number]`
- For a boolean, it will be `[object Boolean]`
- For et tal: `[object Number]`
- For en boolean: `[object Boolean]`
- For `null`: `[object Null]`
- For `undefined`: `[object Undefined]`
- For arrays: `[object Array]`
- ...etc (customizable).

Let's demonstrate:
Lad os demonstrere:

```js run
// copy toString method into a variable for convenience
// kopier toString til en variabel for nemhedens skyld
let objectToString = Object.prototype.toString;

// what type is this?
// hvad type er den?
let arr = [];

alert( objectToString.call(arr) ); // [object *!*Array*/!*]
```

Here we used [call](mdn:js/function/call) as described in the chapter [](info:call-apply-decorators) to execute the function `objectToString` in the context `this=arr`.
Her bruger vi [call](mdn:js/function/call) som beskrevet i kapitlet [](info:call-apply-decorators) til at udføre funktionen `objectToString` i konteksten `this=arr`.

Internally, the `toString` algorithm examines `this` and returns the corresponding result. More examples:
Internt undersøger `toString` algoritmen `this` og returnerer det tilsvarende resultat. Flere eksempler kunne være:

```js run
let s = Object.prototype.toString;
Expand All @@ -186,33 +186,33 @@ let user = {
alert( {}.toString.call(user) ); // [object User]
```

For most environment-specific objects, there is such a property. Here are some browser specific examples:
For de fleste miljøspecifikke objekter, er der en sådan egenskab. Her er nogle browser-specifikke eksempler:

```js run
// toStringTag for the environment-specific object and class:
// toStringTag til miljøspecifikke objekter og klasser:
alert( window[Symbol.toStringTag]); // Window
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest

alert( {}.toString.call(window) ); // [object Window]
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
```

As you can see, the result is exactly `Symbol.toStringTag` (if exists), wrapped into `[object ...]`.
Som du kan se, er resultatet præcis `Symbol.toStringTag` (hvis den eksisterer), omskrevet til `[object ...]`.

At the end we have "typeof on steroids" that not only works for primitive data types, but also for built-in objects and even can be customized.
I enden har vi "typeof on steroids" som ikke kun virker for primitive data typer, men også for indbyggede objekter og endda kan tilpasses.

We can use `{}.toString.call` instead of `instanceof` for built-in objects when we want to get the type as a string rather than just to check.
Vi kan bruge `{}.toString.call` i stedet for `instanceof` for indbyggede objekter, når vi vil have typen som en streng i stedet for blot at tjekke.

## Summary
## Opsummering

Let's summarize the type-checking methods that we know:
Lad os opsummere de type-tjekker, vi kender:

| | works for | returns |
| | virker for | returnerer |
|---------------|-------------|---------------|
| `typeof` | primitives | string |
| `{}.toString` | primitives, built-in objects, objects with `Symbol.toStringTag` | string |
| `instanceof` | objects | true/false |
| `typeof` | primitiver | string |
| `{}.toString` | primitiver, indbyggede objekter, objekter med `Symbol.toStringTag` | streng |
| `instanceof` | objekter | true/false |

As we can see, `{}.toString` is technically a "more advanced" `typeof`.
Som vi kan se er `{}.toString` teknisk set en "mere avanceret" `typeof`.

And `instanceof` operator really shines when we are working with a class hierarchy and want to check for the class taking into account inheritance.
Og `instanceof` operatoren kommer virkelig til sin ret når vi arbejder med en klassehierarki og vil tjekke for klassen med hensyn til arv.