I have an Octree class. A key feature of an Octree is that it can create its own children.
class Octree {
...
createChildren(){
...
/* for each of the 8 new children*/
this.children.push(new Octree(/*someargs*/))
...
}
}
Now I want to inherit off of the Octree class, however, I also want the children to become the inherited class. For example class LODWorldTree extends Octree, to additionally contain some renderer data for a game. However, if I call LODWorldTree.createChildren(), then LODWorldTree.children will be an array of Octrees instead of LODWorldTrees.
What is the best way to fix this problem? While writing this it occured to I could store Octree.myClass = /*some inherited class*/, and manually set this variable for all classes that inherit from Octree. Is there a better way to do something like this? Maybe with this.prototype?
You can utilize the fact that each object has a reference to it's own constructor via the prototype:
class A {
constructor() {
this.val = 1;
this.children = [];
this.typeName = `I'm A`;
}
addSelfChild() {
this.children.push(new this.constructor(this.val + 1));
}
}
let a = new A(1);
a.addSelfChild();
a.addSelfChild();
console.dir(a);
class B extends A {
constructor(val) {
super(val);
this.typeName = `I'm B`;
}
}
let b = new B(1);
b.addSelfChild();
b.addSelfChild();
console.dir(b);
Try to use constructor attribute:
this.children.push(new this.constructor(/*someargs*/));
this.constructor is the reference for constructor for current object, so invoking it will produce new instance of the same class
Related
I have a class A that is a subset of class B. It shares many of the properties and methods of class B.
Class A lacks implementation though. So I want all all functionality in class B to to go into class A.
ClassA.prototype = ClassB.prototype;
or
ClassA.prototype += ClassB.prototype
But it seems I have to:
ClassA.prototype.methodA = ClassB.prototype.methodA
ClassA.prototype.methodB = ClassB.prototype.methodB
ClassA.prototype.methodC = ClassB.prototype.methodC
ClassA.prototype.methodD = ClassB.prototype.methodD
for every single method and property. Is there no way I can put implementations in B into A at once?
It's true you can't overwrite the prototype property of functions created via class syntax, because it's both read-only and non-configurable. You can do it if you use function syntax instead as Fullstack Guy points out.
But you probably want to make ClassA extend ClassB:
class ClassA extends ClassB {
// ...
}
Live Example:
class ClassB {
methodA() {
console.log("methodA");
}
methodB() {
console.log("methodB");
}
methodC() {
console.log("methodC");
}
methodD() {
console.log("methodD");
}
}
class ClassA extends ClassB {
// ...
}
new ClassA().methodA();
If not, though, you can copy all the methods using a loop:
for (const name of Object.getOwnPropertyNames(ClassB.prototype)) {
const method = ClassB.prototype[name];
if (typeof method === "function") {
ClassA.prototype[name] = ClassB.prototype[name];
}
}
Live Example:
class ClassB {
methodA() {
console.log("methodA");
}
methodB() {
console.log("methodB");
}
methodC() {
console.log("methodC");
}
methodD() {
console.log("methodD");
}
}
class ClassA {
// ...
}
for (const name of Object.getOwnPropertyNames(ClassB.prototype)) {
const method = ClassB.prototype[name];
if (typeof method === "function") {
ClassA.prototype[name] = ClassB.prototype[name];
}
}
new ClassA().methodA();
But note that if ClassB is a subclass, super within the methods will continue to access ClassB's superclass methods, it won't either be invalid or access ClassA's superclass methods.
You can use Object.create to make a prototype of ClassA inherit from the prototyoe of ClassB:
function ClassB(){
}
ClassB.prototype.methodA = function(){
console.log("methodA");
}
function ClassA(){
//no implementation
}
//Make the prototype of Class A inherit from the ptottype of Class B
ClassA.prototype = Object.create(ClassB.prototype);
const classA = new ClassA();
classA.methodA();
The above is for function constructors, if you want to use ES6 classes, then you simply need to extend the ClassB:
class ClassB{
methodA(){ console.log("methodA"); }
}
class ClassA extends ClassB{
}
const classA = new ClassA();
classA.methodA();
// When you extend another class, the instance methods of super class are inherited
// in the prototype property of the child class
ClassA.prototype.methodA();
As #T.J. Crowder rightfully said the prototype property of the class Object is not configurable and as result you cannot assign another object to it. Also you cannot change the configurable to true once it has been set to false. The only option is to copy the member functions in a loop.
You can verify this through the Object.getOwnPropertyDescriptor() method:
class ClassA{
}
//configurable and writable is false
console.log(Object.getOwnPropertyDescriptor(ClassA, "prototype"));
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.
In an ES6 class with some instance variables and methods, how can you add a mixin to it? I've given an example below, though I don't know if the syntax for the mixin object is correct.
class Test {
constructor() {
this.var1 = 'var1'
}
method1() {
console.log(this.var1)
}
test() {
this.method2()
}
}
var mixin = {
var2: 'var2',
method2: {
console.log(this.var2)
}
}
If I run (new Test()).test(), it will fail because there's no method2 on the class, as it's in the mixin, that's why I need to add the mixin variables and methods to the class.
I see there's a lodash mixin function https://lodash.com/docs/4.17.4#mixin, but I don't know how I could use it with ES6 classes. I'm fine with using lodash for the solution, or even plain JS with no libraries to provide the mixin functionality.
Javascript's object/property system is much more dynamic than most languages, so it's very easy to add functionality to an object. As functions are first-class objects, they can be added to an object in exactly the same way. Object.assign is the way to add the properties of one object to another object. (Its behaviour is in many ways comparable to _.mixin.)
Classes in Javascript are only syntactic sugar that makes adding a constructor/prototype pair easy and clear. The functionality hasn't changed from pre-ES6 code.
You can add the property to the prototype:
Object.assign(Test.prototype, mixin);
You could add it in the constructor to every object created:
constructor() {
this.var1 = 'var1';
Object.assign(this, mixin);
}
You could add it in the constructor based on a condition:
constructor() {
this.var1 = 'var1';
if (someCondition) {
Object.assign(this, mixin);
}
}
Or you could assign it to an object after it is created:
let test = new Test();
Object.assign(test, mixin);
In es6 you can do this without assigning and you can even invoke the mixin constructor at the correct time!
http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/#bettermixinsthroughclassexpressions
This pattern uses class expressions to create a new base class for every mixin.
let MyMixin = (superclass) => class extends superclass {
foo() {
console.log('foo from MyMixin');
}
};
class MyClass extends MyMixin(MyBaseClass) {
/* ... */
}
You should probably look at Object.assign(). Gotta look something like this:
Object.assign(Test.prototype, mixin);
This will make sure all methods and properties from mixin will be copied into Test constructor's prototype object.
I'm surprised to find that none of the answers mentions what I would consider a mixin in the sense of composition (and in contrast to inheritance), which to me is a function that adds functionality to an object. Here's an example making use of both inheritance and composition:
class Pet { constructor(name) { this.name = name } }
class Cat extends Pet { expression = 'miaow' }
class Dog extends Pet { expression = 'bark' }
class Human { constructor(name, age) { this.name = name; this.age = age; } }
class American extends Human { expression = 'say howdy' }
function canSayHello(...contexts) {
for (const context of contexts) {
context.sayHello = function() {
console.log(`Hello my name is ${this.name} and I ${this.expression}`)
}
}
}
canSayHello(Pet.prototype, Human.prototype); // apply the mixin
const garfield = new Cat('garfield');
const pluto = new Dog('pluto');
const joebiden = new American('Joe Biden', 79);
garfield.sayHello();
pluto.sayHello();
joebiden.sayHello();
If I define two classes as follows...
class A {
getParentInstance(...args) {
return new super.constructor(...args);
}
}
class B extends A {}
console.log((new B).getParentInstance().constructor.name);
Object is logged to the console, instead of my desired A. This is due to the super in A.prototype.getParentInstance referencing the superclass of A specifically which is Object. This is opposed to the alternative, which would be super being relative to the current level in the prototype chain -- for B that would be A.
My question is: Is there a way to define methods in such a way to use the relative super at each level of the prototype chain when inherited? Effectively resulting in...
(new B).getParentInstance().constructor.name === 'A'
You could try something like this
class A {
static getParentConstructor() {
return Object;
}
}
class B extends A {
static getParentConstructor() {
return A;
}
}
var b = new B();
var a = new (b.constructor.getParentConstructor())();
A little Object.getPrototypeOf() magic seems to be the trick:
class A {
getParentInstance(...args) {
const thisProto = this.constructor.prototype;
const RelativeSuperConstructor = Object.getPrototypeOf(thisProto).constructor;
return new RelativeSuperConstructor(...args);
}
}
class B extends A {}
console.log((new B).getParentInstance().constructor.name);
results in the correct "super" being grabbed, and thus logs 'A' as desired.
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.