Edit: this question is different from How to extend a class without having to using super in ES6? - although the answers are related, this is very obviously a different question. It relates to a specific error, and the two main classes involved Person and CreationEvent don't actually inherit from each other.
I have two ES6 classes, Person and CreationEvent (CreationEvent inherits from Event). I wish to to make a new CreationEvent when I make a new Person (as the CreationEvent is part of the events in the history of person's account).
Running new CreationEvent() on it's own works fine. However I can't run new Person().
Even with reduced version of the code still fails:
class Event {
constructor() {
this.time = Date.now()
this.tags = []
}
}
class CreationEvent extends Event {
constructor() {
this.description = "Created"
}
}
class Person {
constructor(givenName, familyName, email) {
var creationEvent = new CreationEvent()
}
}
Running new Person() returns
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
How do I make a new ES6 Object in another Object's constructor?
You need to call super() in the CreationEvent class because it extends the Event class and needs te be initialized. Like this:
class CreationEvent extends Event {
constructor() {
super();
this.description = "Created"
}
}
Related
This question already has answers here:
Access private method in an overriden method called from the base class constructor
(1 answer)
Call a child method from a parent class in ES6
(2 answers)
What's wrong with overridable method calls in constructors?
(8 answers)
Closed 9 days ago.
When I run this code:
'use strict';
class Base {
constructor() {
this._public();
}
}
class Child extends Base {
constructor() {
super();
}
_public() {
this.#privateMethod();
}
#privateMethod() {
this.bar = 1234;
}
}
const c = new Child();
console.log(c.bar);
I get the following error:
this.#privateMethod();
^
TypeError: Receiver must be an instance of class Child
As I understand JavaScript, the receiver in the following code is exactly an instance of the class Child. It's even shown in the dev tools inspector:
So could someone please explain to me what's going on? Is it a bug or what?
Actually FF shows a more accurate error message:
Uncaught TypeError: can't access private field or method: object is not the right class
This is one example of why it's best not to call public instance methods from constructors. When your Base class constructor calls this._public(), Child's initialization is not (yet) complete. The earliest you can use Child members is after super() has returned, not before. It's only after super() returns that Child's automatic initialization (such as setting up private fields and methods, and initializing public properties defined via class fields syntax) is complete. You can see this with public class fields as well:
class Base {
constructor() {
console.log("test" in this); // false
}
}
class Child extends Base {
test; // <== Public class field
constructor() {
super();
console.log("test" in this); // true
}
}
new Child();
You're okay to call this._public() from Child's constructor just after super() returns (although, again, it's best not to call public methods from constructors! better to call #privateMethod directly), because Child will be fully ready by then (other than any initialization you're doing in its constructor, of course), but not before super() returns.
Is there a way to force the class/component initializing a certain class to call one of its functions?
Ex:
class Car
{
public destroy(){...}
}
class Bomb extends React.Component<...>
{
private car: Car = new Car();
}
I wish for whoever initializes Car to call destroy() at some point in the initializing class (Bomb, in this case).
I have an abstract class that does new this(), however, it isn't creating an instance of itself, but it is creating an instance of the class that extended it.
This works in JavaScript when compiled and returns the proper class. However, TypeScript is complaining.
Cannot create an instance of an abstract class.
abstract class Model {
static find<T extends Model>(someVar) {
let inst = new this() as T
// Do some extra stuff with the instance
return inst
}
}
class A extends Model { }
A.find()
The first problem of your solution - it isn't safe, T type may not contain empty constructor. The second problem: even if you call find() on A class, return type will be inferred as Model if it isn't set explicitly.
Because anyway you should specify A type when you call find, it would be better to pass the type constructor to the find method, in this case both problems will be solved.
abstract class Model {
static find<T extends Model>(ModelClass: new () => T, param: string): T {
let inst = new ModelClass()
// Do some extra stuff with the instance
return inst;
}
}
class A extends Model {}
const a = Model.find(A, "param");
How can I execute a function that is aware of a newly created class's name which is derived from a certain parent at the time that the class is extended?
What I currently do:
class component {
constructor() {
// this.constructor.name returns the derived class name on instantiation
// we need to register class components derived from component
registerIfUnknown(this.constructor.name);
}
}
However this means the registerIfUnknown function will be called every time we create a new instance of any subclasses of component. Is there a way to execute a method/function that understands what the class's name is whenever the component class is extended?
I'm learning react from the docs, but not sure what the super() does in this example. Usually, doesn't it take the arguments that are passed to making a new instance and then calls React.Component's constructor method to incorporate these arguments into the instance? What does it do without any arguments?
class LikeButton extends React.Component {
constructor() {
super();
this.state = {
liked: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({liked: !this.state.liked});
}
render() {
const text = this.state.liked ? 'liked' : 'haven\'t liked';
return (
<div onClick={this.handleClick}>
You {text} this. Click to toggle.
</div>
);
}
}
ReactDOM.render(
<LikeButton />,
document.getElementById('example')
);
In ES6, derived classes have to call super() if they have a constructor. In react, all components extend from the Component class.
You don't actually need a constructor for every ES6/react class. If no custom constructor is defined, it will use the default constructor. For base classes, it is:
constructor() {}
And for derived classes, the default constructor is:
constructor(...args) {
super(...args);
}
You also need to call super() before accessing this, since this is not initialized until super() is called.
There are a few reasons to use a custom constructor in react. One is that you can set the initial state within the constructor using this.state = ... instead of using the getInitialState lifecycle method.
You can also bind class methods inside the constructor with this.someClassMethod = this.someClassMethod.bind(this). It's actually better to bind methods in the constructor since they will only be created once. Otherwise if you call bind or use arrow functions to bind methods anywhere outside the constructor (like in the render method), it will actually end up creating a new instance of the function on every render. Read more about that here.
If you want to use this.props in the constructor, you need to call super with props as an argument:
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
If you don't, then this.props is undefined in the constructor. However, you can still access this.props anywhere else in the class outside the constructor without needing to do anything with it in the constructor.
The super keyword in JavaScript is used in order to call the methods of the parent class. By itself, super() is used within a constructor function to call the parent constructor function. For example:
class Animal {
constructor(age) {
console.log('Animal being made');
this.age = age;
}
returnAge() {
return this.age;
}
}
class Dog extends Animal {
constructor (age){
super(age);
}
logAgeDog () {
console.log(`This dog is: ${ super.returnAge()} years old`);
}
}
const dog = new Dog(5);
console.log(dog);
dog.logAgeDog();
In this example we have a Dog class which extends an Animal class. The Dog class uses the super keyword twice. The first occurence is in the constructor, when super() is used in the constructor it will call the parent class constructor. Therefore we have to give the age property as an argument to it. Now the Dog successfully has an age property.
We can also use super outside of the constructor in order to access the parent's 'class' (i.e. prototype) properties and methods. We use this in the logAgeDog function located in the Dog class. We use the following code:
super.returnAge();
You should read this as:
Animal.returnAge(); // superClass.returnAge()
Why do I need this in React?
You need the super() keyword in React only when implementing a constructor. You have to do the following:
constructor(props) {
super(props);
// Don't call this.setState() here!
}
the parent class which is named Component needs to do some initialization on its own in order for React to work fine. If you implement a constructor without a super(props) call this.props in Component will be undefined which can lead to bugs.