I want to pass child class instance to super class using super's constructor but I'm get this error
super(this);
this is not allowed before superclass constructor invocation
Why i'm getting this error , also how could I resolve this issue
class Parent
{
constructor(child)
{
this.child = child;
}
//...somewhere in code
//child.doSomething();
}
class Child extends Parent
{
constructor()
{
super(this); // <==== the error here
}
doSomething = () =>
{
//...
}
}
There's no need to pass this to super() because this inside the superclass constructor will be a reference to the same object. Recall that your class hierarchy will cooperate to perform initialization on a single new object.
Calls to super() must come before any reference to this, including in the super() argument list. Why? Because in order to mimic behavior of other OO languages, it must be the case that the top-most initializer in the class hierarchy gets its hands on the new object first. The parent (or "senior") initializer should be able to assume that prototype methods at that level have the semantics the base class expects, since it doesn't "know" what subclasses might have done with their prototypes etc. If a subclass initializer could modify the new object and override a base class prototype method (or something else of that flavor), it'd be chaos.
In the child's constructor method, the parent's constructor must be called before accessing this. The superclass' constructor will have access to this anyway, since you are constructing an instance of the superclass - though it will not have access to any other initialization that your child constructor may yet do.
Related
I currently am learning ES6 classes for Javascript and I seem to understand the concept of them but I don't understand what a derived class inherits from its base class. Is it the methods of the class? Is it safe to assume that the methods of a class are properties of said class? In which case, they are part of the prototype and are thus inherited by objects down the prototype chain. And what about the constructor? Are properties defined inside the constructor inherited?
Thank you for your consideration!
Classes are more or less just syntactic sugar for setting up prototype inheritance.
class Derived extends Base {}
is equivalent to
function Derived(...args) {
return Base.apply(this, args);
}
Object.setPrototypeOf(Derived, Base);
Object.setPrototypeOf(Derived.prototype, Base.prototype);
There is some "magic" involved with super and in the future with public and private class fields, but the basic relationship between objects is the same.
Is it safe to assume that the methods of a class are properties of said class? In which case, they are part of the prototype and are thus inherited by objects down the prototype chain.
Yes, methods become properties of the corresponding prototype object, from which all instances inherit. I.e.
class Foo {
bar() {}
}
is equivalent to
function Foo() {}
Foo.prototype.bar = function() {}
And since a "base class'" property object is in the prototype chain of the derived class, all its methods are available to instances of the derived class.
Are properties defined inside the constructor inherited?
"Inherited" is the wrong word here. The properties are created on the instance itself since that's how constructors work.
Consider the process to be like this:
// Create new instance
var newInstance = Object.create(Derived.prototype);
// Call base constructor with `this` set to new instance
Base.apply(newInstance);
// Call derived constructor with `this` set to new instance
Derived.apply(newInstance);
If the base constructor contained something like this.base = 42;, then that property would be directly created on the new instance, since this refers to the new instance.
Note: In reality the exact flow is a bit different due to the fact extending built-in classes such as Array need special treatment but the end result is roughly the same.
You didn't ask about static methods but these are still part of the inheritance. static methods become properties of the constructor function itself.
class Foo {
static bar() {}
}
is equivalent to
function Foo() {}
Foo.bar = function() {}
Because the constructor of the base class becomes the prototype of the constructor of the derived class, all properties defined on the base constructor are available to the derived constructor.
The developer tools in your browser can actually show you all of this:
class Base {
static staticBase() {}
constructor() {
this.base = 42;
}
fromBase() {}
}
class Derived extends Base {
static staticDervied() {}
constructor() {
super(); // necessary since we extend base
this.derived = 21;
}
fromDerived() {}
}
console.dir(Derived);
console.dir(new Derived());
there are a lot of great resource about fundamental es06
example - https://exploringjs.com/es6/ch_classes.html#details-of-subclassing
I am new to JS and was learning classes in JS. Also, I found out that in derived class we must use super() which invokes the constructor of parent class. The question is Why do we need to use super() in the constructor of derived class so as to call THE CONSTRUCTOR OF PARENT CLASS. Why should we care about THE CONSTRUCTOR OF PARENT CLASS. Here is the example:
class Car{
constructor(speed)
{
this.speed=speed
}
}
class BMW extends Car
{
constructor(speed)
{
super(speed);
}
}
Even if we do not want to use "speed" in derived class we anyways need to use super in derived class
You can simply call super without parameter if you don't need them:
class BMW extends Car
{
constructor()
{
super();
}
}
all I want to understand is why we need to use super() in the constructor of derived class.
If you don't use, then it'll create its own constructor rather than parent class constructor inheritance. That is, you will be avoiding to duplicating constructor part when using super.
BTW, in ES7, even if you don't use constructor, it will inherit from parent class.
You don't have to create a constructor in the child class if you don't have any initialization work to do. In this case the construction in automatically inherited from the parent class (the closest parent that has a constructor).
However, when you are defining a constructor in the child class you need to call super() to initialize the object. The this property is not available before calling this function as the object wasn't created just yet.
Let's say I have two ES6 classes like this:
class Base {
static something() {
console.log(this);
}
}
class Derived extends Base {
}
And then I make a call like this:
Derived.something();
Note that I am making a call to a static method defined on the super class via sub class.
This does not give me errors. It prints
[Function: Derived]
So accessing this within a static method seems to work here.
I need a common static method for all sub-classes of a super class and I need to be able to know what sub-class is calling this method.
Now my question is whether using this within a static method is legal. I know these static methods become class methods, and hence this would naturally point to the class object they are called on. (The class object being the constructor.)
But I can't seem to find any definitive resource that states that this is allowed by the ES specification.
This looks like a good introduction to ES6 classes but does not talk about this with static.
Under typical circumstances, the this in any call to something.method() will refer to something as long as the function is not an arrow function, bound function, or something like that (and it is neither of those in this case).
Class inheritance, or even ES6, aren't really relevant here. All you need to know is that you are calling Derived.something(), so this will refer to Derived.
Yes, this is legal in static methods, that's the way this should be done.
this refers to class instance in prototype methods and refers to class constructor in static methods, unless a method was unbound from its original context.
Similarly, super refers to parent class prototype in instance methods and refers to parent class constructor in static methods.
As long as the static method is invoked as a member expression, e.g.
Derived.something();
as opposed to
const { something } = Derived;
something();
then this will refer to Derived. Derived.something() is identical to something.call(Derived) if Derived.something is stored to an intermediate variable, because that's how a member expression with a nested call expression is evaluated, essentially.
How to get (console.log for ex.) B class's methods in A class's constructor?
class A {
constructor() {
// GET B's method names ('ok', ...) here
}
}
class B extends A {
constructor() {
super();
}
ok() {
}
}
In the "base" constructor you have access to complete object, so can check what is its real constructor and so its prototype const childClassPrototype = this.constructor.prototype. Having a "child" prototype you can get a list of its properties with Object.getOwnPropertyNames(childClassPrototype). From that list you want to filter out "constructor" and properties that are not functions.
Note: this technique will only give you access to "leaf" prototype, once you may have a multi level prototype chain. Thus you have to iterate over prototype chain.
Note2: for autobinding you may like to consider using a decorator. One implementation is here: https://github.com/andreypopp/autobind-decorator - this technique gives you better control over unexpected behavior that may come from metaprogramming
Use either new.target.prototype or Object.getPrototypeOf(this) to get the prototype object of the instantiated subclass. Then traverse the prototype chain to all superclasses, and get the own properties of each object. Don't forget non-enumerable properties.
Of course, using this in a constructor for more than logging/debugging purposes is a code smell. A class should not need to know about its subclasses. If you want to do autobindings, let each subclass constructor autobind its own methods.
seen this JavaScript pattern in some large projects, which "copies" or "implements" ClassA's properties to ClassB, but couldn't figure out what is the purpose of calling ClassA's empty constructor inside ClassB's constructor using ".call()" while passing the ClassB instance as "this" binding?
var ClassA = function() {
//this function is totally empty
};
ClassA.prototype = {
jump: function() {...some code...},
dance: function() {
if (this.canDance) {
alert("dance");
}
}
};
ClassA.implementOn = function(targetClassOrObject) {
for ( var prop in ClassA.prototype ) {
targetClassOrObject[ prop ] = ClassA.prototype[ prop ];
}
};
var ClassB = function() {
this.canDance = true;
ClassA.call(this); // <------------What's the purpose of this line?
};
ClassA.implementOn(ClassB.prototype);
var instanceOfB = new ClassB();
instanceOfB.dance();
If the ClassA constructor is empty, there's no big surprise here -- calling ClassA's empty constructor does absolutely nothing.
The moment you decide you want ClassA's constructor to be non-empty, however, you'll see that line now has a tremendously important effect: constructing a ClassB object also invokes the ClassA-specific constructor behaviors in the context of newly-constructed ClassB object, which is what you'd expect if ClassB is a logical "subclass" of ClassA.
(Of course, JavaScript doesn't have proper "subclasses", but this is obviously an attempt to implement class-based behavior in the language.)
purpose of calling ClassA's empty constructor inside ClassB's constructor using ".call()"
To have the script still working when ClassA will not be empty. Of course, currently it does nothing, but that might change in future. So it is good practise to implement the full inheritance pattern, making it easier to change the code later without introducing bugs.
Once ClassA changes to implement custom instance-specific properties - which are set up in the constructor, you want to have them on ClassB instances as well. Therefore, you invoke the ClassA constructor on ClassB instances as well during their initialisation.
If the ClassA constructor is empty (like in your example code), then yeah, it does nothing.
The reason you see this pattern though, is for the times when it's not. It's analogous to a super call in a class-based OO language.
If you have to do some work in the ClassA constructor to get an object that's in a correct state, it's likely you'll want to do the same work in a "subclass". Just copying the prototype's properties may not be enough.
With .call, you can change the value of this in the called method to the argument you specify. ClassA.call(this) calls the ClassA constructor with ClassB as the context. This allows you to use the properties of ClassB in ClassA methods. The methods are all copied to ClassB via ClassA.implementOn.
You will notice that (new ClassA()).dance() does nothing, but (new ClassB()).dance() alerts "dance" because this.canDance is true.
Demo: http://jsfiddle.net/5v7xh/