Skip to content

Commit

Permalink
Complete docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh-Cena committed Jul 17, 2024
1 parent e6fef1e commit cd273f1
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ page-type: javascript-error

{{jsSidebar("Errors")}}

The JavaScript exception "super() is only valid in derived class constructors" occurs when the {{jsxref("Operator/super", "super()")}} call is used somewhere that's not the body of a [constructor](/en-US/docs/Web/JavaScript/Reference/Classes/constructor) in a class with [`extends`](/en-US/docs/Web/JavaScript/Reference/Classes/extends) keyword.
The JavaScript exception "super() is only valid in derived class constructors" occurs when the {{jsxref("Operators/super", "super()")}} call is used somewhere that's not the body of a [constructor](/en-US/docs/Web/JavaScript/Reference/Classes/constructor) in a class with [`extends`](/en-US/docs/Web/JavaScript/Reference/Classes/extends) keyword.

## Message

Expand All @@ -24,7 +24,7 @@ SyntaxError: super is not valid in this context. (Safari)

The `super()` call is used to invoke the base constructor of a derived class, so the base class can initialize the {{jsxref("Operators/this", "this")}} object. Using it anywhere else doesn't make sense.

Note that `super()` can be defined in a function, as long as that function is nested within the constructor. However, this function must be then immediately called within the constructor and can't be deferred to be called later, because `super()` must be called exactly once before the constructor returns and cannot be called more than once.
`super()` can also be defined in an arrow function that's nested within the constructor. However, it cannot be defined in any other kind of function.

## Examples

Expand All @@ -42,8 +42,10 @@ class Base {

You cannot call `super()` in a class method, even if that method is called from the constructor:

```js example-bad
class Base {
```js example-ba
class Base {}

class Derived extends Base {
constructor() {
this.init();
}
Expand Down Expand Up @@ -74,7 +76,9 @@ Object.setPrototypeOf(Derived, Base);
You can call `super()` before calling any other method in the constructor:

```js example-good
class Base {
class Base {}

class Derived extends Base {
constructor() {
super();
this.init();
Expand All @@ -86,14 +90,16 @@ class Base {
}
```

You can call `super()` in a function that's nested within the constructor:
You can call `super()` in an arrow function that's nested within the constructor:

```js example-good
class Base {
class Base {}

class Derived extends Base {
constructor() {
function init() {
const init = () => {
super();
}
};

init();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,40 @@ TypeError: AsyncIterator cannot be constructed directly (Safari)

## What went wrong?

The {{jsxref("Iterator")}} and {{jsxref("AsyncIterator")}} constructors are abstract classes and should not be used directly. They check the value of [`new.target`](/en-US/docs/Web/JavaScript/Reference/Operators/new.target) and throw if it is the same as the constructor itself. The only way to use these constructors is to inherit from them in a subclass and call `super()` in the subclass constructor. The subclass must also define a `next()` method to be useful.

## Examples

### Invalid cases

```js example-bad
new Iterator();
```

### Valid cases

```js example-good
class MyIterator extends Iterator {
#step;
#end;
constructor(start, end) {
// Implicitly calls new Iterator(), but with a different `new.target`
super();
this.#step = start;
this.#end = end;
}
next() {
if (this.#step < this.#end) {
return { value: this.#step++, done: false };
} else {
return { done: true };
}
}
}

new MyIterator();
```

## See also

- {{jsxref("AsyncIterator")}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ page-type: javascript-error

{{jsSidebar("Errors")}}

The JavaScript exception "derived class constructor returned invalid value x" occurs when a derived class constructor
The JavaScript exception "derived class constructor returned invalid value x" occurs when a derived class constructor returns a value that is not an object or `undefined`.

## Message

Expand All @@ -22,10 +22,44 @@ TypeError: Cannot return a non-object type in the constructor of a derived class

## What went wrong?

Typically, a constructor does not need to return anything—the value of `this` is automatically returned when the class is constructed. A constructor can also return an object, and this object will override `this` as the newly constructed instance. However, returning something that's neither an object nor `undefined` is usually a mistake, because that value is ignored. In base classes and function constructors (using the `function` syntax), returning such a value is silently ignored, while in derived classes, it throws an error.

## Examples

### Invalid cases

```js example-bad
class Base {
constructor() {}
}

class Derived extends Base {
constructor() {
return 2;
}
}

new Derived(); // TypeError: derived class constructor returned invalid value 2
```

### Valid cases

```js example-good
class Base {
constructor() {}
}

class Derived extends Base {
constructor() {
return { x: 1 };
}
}

new Derived(); // { x: 1 }
```

## See also

- [Classes](/en-US/docs/Web/JavaScript/Reference/Classes)
- {{jsxref("Classes/extends", "extends")}}
- {{jsxref("Operators/new", "new")}}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ page-type: javascript-error

{{jsSidebar("Errors")}}

The JavaScript exception "super() called twice in derived class constructor" occurs when
The JavaScript exception "super() called twice in derived class constructor" occurs when the {{jsxref("Operators/super", "super()")}} is called a second time for a given derived class constructor.

## Message

Expand All @@ -22,8 +22,63 @@ ReferenceError: 'super()' can't be called more than once in a constructor. (Safa

## What went wrong?

The `super()` call can only be called at most once for each `new` call to a derived class constructor. This is because `super()` is responsible for initializing the parent class, and calling it more than once would result in the parent constructor being called multiple times.

The best way to prevent this is to ensure that `super()` is placed outside of any control flow structure. Otherwise, make sure that all code paths in the constructor lead to only one `super()` call.

The `super()` call can be "saved" in an arrow function nested within the constructor. Then, when you call the arrow function, you will also call `super()`, and the same rule applies: the arrow function can only be called at most once.

## Examples

### Invalid cases

```js example-bad
class Base {}

class Derived extends Base {
constructor() {
super();
super();
}
}
```

Sometimes the bug may be more subtle.

```js example-bad
class Base {
constructor(flavor) {
// Do something with the flavor
}
}

class Derived extends Base {
constructor(flavors) {
if (flavors.includes("chocolate")) {
super("chocolate");
}
if (flavors.includes("vanilla")) {
super("vanilla");
}
}
}
```

Originally, `flavors` may never simultaneously include both "chocolate" and "vanilla", but if that ever happens, the constructor will call `super()` twice. You need to rethink about how your class should be structured to avoid this issue.

### Valid cases

```js example-good
class Base {}

class Derived extends Base {
constructor() {
super();
// More initialization logic
}
}
```

## See also

- [Classes](/en-US/docs/Web/JavaScript/Reference/Classes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ page-type: javascript-error

{{jsSidebar("Errors")}}

The JavaScript exception "must call super constructor before using 'this' in derived class constructor" occurs when
The JavaScript exception "must call super constructor before using 'this' in derived class constructor" occurs when the {{jsxref("Operators/super", "super()")}} is not called for a given derived class constructor, and the derived constructor tries to access the value of {{jsxref("Operators/this", "this")}}, or the derived constructor has already returned and the return value is not an object.

## Message

Expand All @@ -22,8 +22,45 @@ ReferenceError: 'super()' must be called in derived constructor before accessing

## What went wrong?

The `super()` call can only be called at most once for each `new` call to a derived class constructor. Often, you need to call it exactly once, because if you don't call it, the parent constructor cannot initialize the value of `this`, so you cannot access `this` in the derived constructor and the `this` is not considered a valid constructed object (and throws if the derived constructor completes in this state). The way around it is to return an object from the derived class constructor, in which case the object returned will be used as the constructed object instead of `this`, allowing you to not call `super()`. This is rarely done though.

## Examples

### Invalid cases

```js example-bad
class Base {
constructor() {
this.x = 1;
}
}

class Derived extends Base {
constructor() {
console.log(this.x);
// The Base constructor is not called yet, so this.x is undefined
// ReferenceError: must call super constructor before using 'this' in derived class constructor
}
}
```

### Valid cases

```js example-good
class Base {
constructor() {
this.x = 1;
}
}

class Derived extends Base {
constructor() {
super();
console.log(this.x); // 1
}
}
```

## See also

- [Classes](/en-US/docs/Web/JavaScript/Reference/Classes)
Expand Down

0 comments on commit cd273f1

Please sign in to comment.