What exactly does a derived class inherit from its base class? - javascript

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

Related

Understanding the prototype created from a `new` instance

From the new MDN docs it says:
The new keyword does the following things:
Creates a blank, plain JavaScript object.
Adds a property to the new object (__proto__) that links to the constructor function's prototype object
How exactly is the prototype defined then? My thought was it would be:
If it's in a function (not using the class keyword), it would lookup to find if there is a [Constructor].prototype declared somewhere and use that, and if not it would fallback to...(not sure?). As an example if the constructor is named Range it would lookup to see if Range.prototype is defined and use that as the prototype.
If it's in a class then it would use every method or property to build the prototype up.
Is that more-or-less a correct understanding, or what might I be missing?
No matter whether the constructor is declared with class syntax or as a function, the <constructor.prototype> object will always exist, even if never explicitly referred to. Example:
function FooFn() {}
class FooClass{}
console.log(FooFn.prototype);
console.log(FooClass.prototype);
These .prototype objects are plain objects which become the internal prototype of instances created with new. They also have a .constructor property pointing to the constructor (the function / class used to create an instance).
So it's not exactly that
it would lookup to find if there is a [Constructor].prototype declared somewhere and use that
but rather that such a property always exists on functions and classes, and when an instance is created with new, the object inside the .prototype property becomes the internal prototype of the instance.
If it's in a class then it would use every method or property to build the prototype up.
Not exactly - a class is mostly just syntactic sugar for a function. What this does:
class Foo {
method() {
console.log();
}
}
is almost exactly (but not entirely) the same as
function Foo() {}
Foo.prototype = function method() {
console.log();
}
The methods are assigned to the class's .prototype object when the class declaration happens, not when an instance is created.
class X {
xMethod() {
}
}
console.log(X.prototype);
console.log(X.prototype.hasOwnProperty('xMethod'));
console.log(X.prototype === (new X).__proto__);

what's the "Object" really mean in Object constructor?

I'm from Java/C# background, the traditional OOP language. it is really hard for me understand javascript world. Below is an example and my questions:
var o = new Object(123);
Q1- is the Object in new Object() actually a function like
function Object() {
...
}
Q2- if the answer to question 1 is yes then I'm confused with Object.prototype, that means prototype is a property for object function, so how can a function has its property? so how can we add a new property in a function like
function Object() {
...
prototype: ... //obviously this is not the right syntax
}
can any body provides me a skeleton code for this?
Q3- what I check console.log(typeof Object), the output is "function", since an function is also an object, so why the output is not "object"
Yes Object is a function in new Object(123).
Older version like ES5 class is written like this pattern
function MyClass () {
// .....
}
But in ES6 the original class keyword can be used like Java/C#
class MyClass
{
constructor() {
// ...
}
}
In JavaScript the prototype is used to inherit the class properties and this concept for the older version of ES6
According to MDN documentation the Object.Prototype is
Nearly all objects in JavaScript are instances of Object; a typical object inherits properties (including methods) from Object.prototype, although these properties may be shadowed (a.k.a. overridden). However, an Object may be deliberately created for which this is not true (e.g. by Object.create(null)), or it may be altered so that this is no longer true (e.g. with Object.setPrototypeOf).
Changes to the Object prototype object are seen by all objects through prototype chaining, unless the properties and methods subject to those changes are overridden further along the prototype chain. This provides a very powerful although potentially dangerous mechanism to override or extend object behavior.
Prototype Example:
Consider the following Employee class
function Employee()
{
this.organization = 'xyz';
}
If you want to add a function details property to that Employee class, then you can use prototype. Example:
Employee.prototype.details = function()
{
this.age = 26;
this.designation = 'Software Engineer';
// ....
}
Now, create the object of that Employee class
var emp = new Employee();
console.log(emp.organization, emp.age, emp.designation);
Notice that you can access age and designation what you are inherited using prototype.

this is not allowed before superclass constructor invocation

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.

JavaScript: How to get child Class's methods in parent's constructor?

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.

ES6 - Super required in constructor

class Overflow {}
class Stack extends Overflow {
constructor() {
super();
}
}
let stack = new Stack();
https://plnkr.co/edit/JqRfuDAav9opvapwCGpT?p=preview
If I use construtor() I must call super() always.
Why isn't super() auto called in constructor?
Edit: Is super() here calling the base constructor AND setting the prototype? Seems wrong.
Edit: Why is super() required? Even when I've no intention of calling the base constructor.
Why isn't super() auto called in constructor?
So you can decide where in the constructor to call it. This is perfectly valid, for instance:
constructor(foo) {
let bar;
if (foo) {
bar = /*...*/;
} else {
bar = /*...*/;
}
super(bar);
}
...provided no code prior to the call to super uses this (or super.xyz).
Yes, it would have been possible to define the language such that if you didn't have any call to super in your constructor at all, it was added automatically for you at the beginning (a'la Java), but they just decided not to do it that way.
Is super() here calling the base constructor AND setting the prototype? Seems wrong.
No, it's calling the base constructor. The prototype was set before your constructor was called. It's exactly like this old ES5 code:
function Derived() {
Base.call(this);
}
...in:
function Base() {
}
function Derived() {
Base.call(this);
}
Derived.prototype = Object.create(Base.prototype);
Derived.prototype.constructor = Derived;
Why is super() required? Even when I've no intention of calling the base constructor.
If you have no intention of calling the base constructor, then your subclass isn't a subclass and shouldn't be extending the base. In a strictly-typed language you'd probably make the base (or a subset of the base) an interface and have your class implement that rather than subclassing. In JavaScript, no need, just make it quack like the duck you want it to be. If an instanceof relationship is important, create a new base that will act like an interface but doesn't do anything anywhere, and have the old base and your class subclass it directly.
Axel FTW
http://www.2ality.com/2015/02/es6-classes-final.html
Summary
Why super is required?
The new keyword class isn't just syntax sugar.
Allocation and instantiation only happens in the base constructor.
But why this?
To allow exotic objects to be extended (thank you Felix Kling).

Categories