JavaScript - Class extend on condition - javascript

Here is the thing. I have a main class called A.
I want this class to extend class B.
class A extends B {}
But in fact, I want the class B to extend C, D or E on a specific condition:
class B extends B1 {}
or
class B extends B2 {}
or
class B extends B3 {}
So the B class would be a "fake" class, just to check a condition and then extend the right class.
In the final, the result would be the same as:
class A extends B1 {}
or
class A extends B2 {}
or
class A extends B3 {}
I know this is possible in PHP, with abstract classes or wrapper classes for example.
But how to do that in JavaScript ES6?
Thanks

Weird, but possible:
class subClassFirst {
report() {
console.log(`Extended ${this.name} from the first class`);
}
}
class subClassSecond {
report() {
console.log(`Extended ${this.name} from the second class`);
}
}
class subClassThird {
report() {
console.log(`Extended ${this.name} from the third class`);
}
}
function classCreator(condition) {
let sub;
switch (condition) {
case 'first':
sub = subClassFirst;
break;
case 'second':
sub = subClassSecond;
break;
case 'third':
sub = subClassThird;
break;
}
return (class extends sub {
constructor(name) {
super();
this.name = name;
}
});
}
let myClass;
myClass = classCreator('first');
let mcf = new myClass('f');
myClass = classCreator('second');
let mcs = new myClass('s');
myClass = classCreator('third');
let mct = new myClass('t');
mcf.report();
mcs.report();
mct.report();

I found blog post that gave an easy es6 way that doesn't use util.inherits
https://www.mikedoesweb.com/2017/dynamic-super-classes-extends-in-es6/
Here is how I used a passed option to determine which class to extend and then obfuscated that in the export
import ClassB from ' '
import ClassA from ' '
const ext = {
classA: ClassA, // the default
classB: ClassB
// can do as many as you want
}
function ExtendsMyClass (opts= {}) {
if (!new.target) {
throw new Error('Uncaught TypeError: Class constructor Interrupt cannot be invoked without \'new\'')
}
// one could vet opts here too including opts.extend
class MyClass extends ext[opts.extend || 'classA'] {
constructor(opts = {}) {
super(opts)
....
}
} // end MyClass
return new MyClass(opts)
} // end dynamic extend
export default ExtendsMyClass
export { ExtendsMyClass as MyClass }
I'll probably make this into "wrapper" utility function that accepts also the child class as well. That way one can dynamically extend any class as opposed to the one off implementation above. Could even implement dynamic imports if it was set up an async function.

So classes in javascript are really not setup in the same classical inheritance way as other languages, the best way to do what you want is to set the prototype of the object you are dealing with. There are a few ways.
Object.setPrototypeOf(currentObj, newPrototype);
Where newPrototype is the object you are wanting to inherit from. Here are a couple good articles on it if you want to learn the inner workings.
http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/
https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch5.md

There's a Node JS function for that
const util = require("util");
class MySubClass {}
class MySuperClass {}
util.inherits(MySubClass, MySuperClass);

Related

Can't use "super.member.Func()" in javascript. How to rewrite it correctly?

super in JS
In this I read what can't use super as it:
class Base {
baseField = 10;
}
class Extended extends Base {
extendedField = super.baseField; // undefined
}
My code is:
class Parent{
ext_class;
constructor(ext){
this.ext_class=ext;
}
}
class Child extends Parent{
constructor(ext){
super(ext);
}
Method(p){
super.ext_class.ExecFunc(p);
}
}
I can't call function from object in member of parent class. I can save it in child but not sure what it is right.
How do I write it correctly?
class Base {
constructor(bf){
this.baseField = bf
}
}
Base.prototype.baseField = 1;
class Extended extends Base {
constructor(bf){
super(bf)
}
extendedField = super.baseField;
}
console.log(new Extended(12).extendedField);
This not work correctly too.
But this work how I need!!!
class Base {
constructor(bf){
Base.prototype.baseField = bf
}
}
class Extended extends Base {
constructor(bf){
super(bf)
}
extendedField = super.baseField;
}
console.log(new Extended(13).extendedField);
I think you should've scrolled further down:
Note that instance fields are set on the instance instead of the constructor's prototype, so you can't use super to access the instance field of a superclass.
That means you'd have to put the property on the prototype explicitly like this:
class Base {}
Base.prototype.baseField = 10;
class Extended extends Base {
extendedField = super.baseField;
}
console.log(new Extended().extendedField);

How to reuse a class method defined in one class which can be used in another class in typescript?

So, I'm new to Typescript, and recently started learning from documentation. I was looking at its documentation and there were no signs of reusing method from other class.
Class A file
export class A{
... constuctor(){
const queue = this.createQueue()
}
createQueue(){
console.log("Has access to this", +this);
}
}
And there is a class B with exact same definations and uses the same method. How do I make this reusable so that, both of them call with "this"?
One solution I thought of is to create a seperate helper Class that could I use, but I'm not sure how to do that.
Any thoughts?
In this case, inheritance would probably be your best bet. This basically means that you can extend upon another class and include all of the other one's properties/getters/setters/methods.
// we denote this class as abstract because it must be extended and cannot be directly initialized, i.e. new BaseFoo()
abstract class BaseFoo<T> { // `T` is the item type within the queue
queue: T[];
constructor() {
this.queue = this.createQueue();
}
createQueue() {
// can access `this`
return [];
}
}
class FooA extends BaseFoo<number> {
constructor() {
super(); // runs child class's constructor
console.log(this.queue); // []
}
}
class FooB extends BaseFoo<string> {
constructor() {
super();
console.log(this.queue); // []
}
}
TypeScript Playground Link

JavaScript ES6 inherintance kills properties in classes?

This is example of very basic code:
"use strict";
class aClass {
readFromA() {
console.log(this.a);
}
constructor() {
this.a = 5;
}
}
class bClass extends aClass {
readFromB() {
console.log(this.a);
}
constructor() {
super();
this.a = 10;
}
}
let bc = new bClass();
bc.readFromA(); //10
bc.readFromB(); //10
My intention is to involve the most modern techniques of object programming in JS. ES6 introduces classes and inheritance of them. It seems to be useless programming style yet. For example, code above overrides property "a" in class aClass by the same variable name in bClass. .
Lets assume that 2 proggramers create those classes. Each of them doesn't know what variable names will be used. If they both use the same variable name - it will couse a catastrophy! Both classes will read and write the same property making application crash. How to protect properties in classes against overriding and be able to utilize "extends" functionality?
Each of them doesn't know what variable names will be used. If they both use the same variable name - it will cause a catastrophy!
This is of course a very bad practice. You should not inherit from classes that you don't know, and every class should document its public members for exactly this purpose.
How to protect properties in classes against overriding and be able to utilize "extends" functionality?
Don't use the same keys. If you cannot ensure this using proper documentation or naming conventions, symbols were made to solve exactly this problem.
const a = Symbol("a");
export default class {
constructor() {
this[a] = 5;
}
readFromA() {
console.log(this[a]);
}
}
import ClassA from '…';
const a = Symbol("a"); // a different symbol than that in the AClass module
class BClass extends AClass {
constructor() {
super();
this.a = 10;
this[a] = 15;
}
readFromB() {
console.log(this.a, this[a]);
}
}
const x = new BClass();
x.readFromA(); // 5
x.readFromB(); // 10, 15
In the meantime I found solution to mentioned problem of private properties in classes. Bergi's idea was implemented. Here is the code:
"use strict";
let aClass = (function () {
let a = Symbol("a");
class aClass {
readFromA() {
console.log(this[a], this.b);
}
constructor() {
this[a] = "aaa"; //this is private
this.b="bbb"; // this is public
}
}
return aClass;
})();
let bClass = (function () {
let a = Symbol("a");
class bClass extends aClass {
readFromB() {
console.log(this[a], this.b);
}
constructor() {
super();
this[a] = "ccc"; //this is private
this.b="ddd"; // this is public
}
}
return bClass;
})();
let bc=new bClass();
bc.readFromA();
bc.readFromB();
The result is:
aaa ddd
ccc ddd
Thanks to encapsulation I managed with using the same property name "a" in both classes which receives different values for each of them. Property "b" is public and can be overriden. With this approach, we do not have to be careful using property names in both classes. There is no risk of accidentally overwriting the non public properties of the base class.
Moreover, this kind of encapsulation allows to use inheritance of classes in traditional way: by "extends" keyword.

extended class, doesn't have its own methods

I try to extend a class with another, who has its constructor overrode, but when i instance this class, it doesn't have its own methods, but has its own properties.
Here's an example which doesn't work properly:
class A {
constructor () {
return {
pi: 3.14
}
}
}
class B extends A {
constructor () {
super();
this.c = 10;
}
d () {}
}
let b = new B();
console.log(b);
Here, b is :
Object {
c:10,
pi:3.14
}
So why the 'd' method is missing ?
EDIT:
Here is a concrete case:
I need to extend a class with HTMLElement, which i can instance and use like html element without registering with document.registerElement.
My code is:
class Element{
constructor(){
return document.createElement('div');
}
}
class Editor extends Element{
constructor(){
super();
}
}
and i want to use my class like this:
let editor = new Editor();
document.querySelector('body').appendChild(editor);
ECMAScript6 class methods are methods of an object's prototype object. You will find the method not in the object itself, but in obj.__proto__.
https://reinteractive.com/posts/235-es6-classes-and-javascript-prototypes
Here you can see and maybe understand what is going on internally with prototyped objects. And yes, the ES6 syntax is just a syntax change, not a new technology.

Is there a way to discover if a javascript 6 class defines its own constructor?

Is there any way to determine if a subclass implements a constructor from within a static method (in a base class)?
I'm trying to write a static create method (that acts like the new keyword) that by default works by passing attribute values as a properties object:
class Person extends Class {
greet() { return 'hello from ' + this.name; }
}
var p = Person.create({name: 'world'}; // create a new Person object and set its `name` property to `'world'`
console.log(p.greet()); // => "hello from world"
but hands off to the class' constructor if it has one:
class Person2 extends Class {
constructor(name) {
super();
this.name = name;
}
greet() { return 'hello from ' + this.name; }
}
var p = Person2.create('world');
console.log(p.greet()); // => "hello from world"
I'm stuck at finding out if the subclass defines its own constructor..
class Class {
static create(...args) {
let has_ctor = ?? // true iff the current subclass defines a constructor..
if (has_ctor) {
// let the constructor handle everything
return new this(...args);
} else {
// assume that `args` contains exactly 1 pojo that defines instance variables to be overridden..
var instance = new this();
let props = args[0];
for (let prop in props) instance[prop] = props[prop];
return instance;
}
}
}
is this even possible?
Seems like it would be much easier to do
class Class {
static create(...args) {
// let the constructor handle everything
return new this(...args);
}
constructor(props){
Object.assign(this, props);
}
}
then if things override the constructor, then can choose to pass props to super() or to assign them manually themselves.
Just to answer your original question
Is there a way to discover if a javascript 6 class defines its own constructor?
No, there is not. Every class does have its own constructor, because a "class" basically is just the constructor function.
If a class definition does not include a constructor method, then it is automatically supplied by the language (see §14.5.14); either as
constructor(...args){ super (...args);}
if there is a super class or as
constructor(){ }
if there is none. The result is not distinguishable from a class where such a constructor was explicitly declared.

Categories