Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES6 use `super` out of class definition

I'm trying to add extra methods to class, and these extra methods should use the super methods.

If I add them in the model definition, it works.

class A {
    doSomething() {
        console.log('logSomething');
    }

}

class B extends A {
    doSomething() {
        super.doSomething();
        console.log('logSomethingElse');
    }
}

If I try to add the extra method to B.prototype, I'll get SyntaxError: 'super' keyword unexpected here.

class A {
    doSomething() {
        console.log('logSomething');
    }

}

class B extends A {
}

B.prototype.doSomething = function doSomething() {
    super.doSomething();
    console.log('logSomethingElse');
}

It is quite clear, why I get this error. This is a function and not a class method.

Let's try to define the method as a class method, and copy it to the original B class:

class A {
    doSomething() {
        console.log('logSomething');
    }

}

class B extends A {}

class X {
    doSomething() {
        super.doSomething();
        console.log('2 logSomethingElse');
    }
}

B.prototype.doSomething = X.prototype.doSomething;

In this case I'll get TypeError: (intermediate value).doSomething is not a function.

Is there any way to define methods (that refer to super) outside from the original class definition, and add these methods later to the original class?

like image 694
Adam Avatar asked Oct 18 '17 08:10

Adam


2 Answers

super refers to ancestor of a class where the method was defined, it isn't dynamic. As Babel output illustrates this, super is hard-coded to Object.getPrototypeOf(X.prototype), and thus orphan class like this one doesn't make sense because it doesn't have super:

class X {
    doSomething() {
        super.doSomething();
        ...
    }
}

But super can be substituted with dynamic counterpart:

doSomething() {
    const dynamicSuper = Object.getPrototypeOf(this.constructor.prototype);
    // or
    // const dynamicSuper = Object.getPrototypeOf(Object.getPrototypeOf(this));
    dynamicSuper.doSomething();
    ...
}

class B extends A {}
B.prototype.doSomething = doSomething;

In this case it will refer to ancestor class of class instance where doSomething was assigned as prototype method.

like image 190
Estus Flask Avatar answered Sep 22 '22 15:09

Estus Flask


While I think this could be assumed as anti-pattern, you shouldn't use super outside from a class.

You can achieve that using Object Literals.

Refer to Object.setPrototypeOf

const A = {
  sayHello() {
    console.log("I am A");
  },
  
  Factory() {
    return Object.create(this);
  }
}

const B = {
  sayHello() {
   super.sayHello();
  }
}

Object.setPrototypeOf(B, A);

const c = B.Factory();

c.sayHello();
like image 20
Hitmands Avatar answered Sep 25 '22 15:09

Hitmands