# Reflect.super

**URL:** <https://es.discourse.group/t/reflect-super/509>\
**Category:** 💡 Ideas\
**Tags:** proposal\
**Created:** [October 21, 2020, 5:23pm UTC](https://es.discourse.group/t/reflect-super/509 "2020-10-21T17:23:43Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![robbiespeed](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/robbiespeed/32/2544_2.png) [@robbiespeed](https://es.discourse.group/u/robbiespeed)\
**Post date:** [October 21, 2020, 5:23pm UTC](https://es.discourse.group/t/reflect-super/509/1 "2020-10-21T17:23:43Z")

</div>

Currently we have `Reflect.construct` which allows creating an instance of a specified class or constructor function, but we can't run a constructor with an existing instance as the `this` value, since `function.apply` and `function.call` cannot be used on class constructors.

I propose adding `Reflect.super(target, thisArgument, argumentList[, newTarget])`. As such extending a class with a constructor function would look something like this:

```javascript
class A {
  constructor () {
    this.x = 1;
  }
  get y () {
    return 2;
  }
}

function B () {
  Reflect.super(A, this, [], B);
  this.z = 3;
}
B.prototype = Object.create(A.prototype);

```

It's very similar to `Reflect.apply` with the added ability that it works on class constructors and can pass a value for `new.target`.

It can be polyfilled using `Reflect.construct`:

```javascript
Reflect.super = function (target, thisArgument, argumentList, newTarget) {
  Object.assign(
    thisArgument,
    Reflect.construct(target, argumentList, newTarget)
  );
}

```

Having it built in would be much more desirable since the polyfill has to create an additional instance for each call.

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [October 21, 2020, 6:46pm UTC](https://es.discourse.group/t/reflect-super/509/2 "2020-10-21T18:46:25Z")

</div>

> [@robbiespeed](#):
>
> we can't run a constructor with an existing instance as the `this` value

Yes. Since ES6, a constructor is not just a method that _could_ be called on a value to initialise it, it actually does what the name says: it constructs a new object. This is also how a `super()` call works: it asks the parent class to construct a new instance, and then uses that as the `this` value for the current constructor to initialise. There is no `thisArgument` getting passed to the parent constructor.

So `Reflect.super` doesn't make sense from a naming perspective. Also, `Reflect` is a (admittedly, badly named) namespace for the default implementations of `Proxy` traps, and there is no `super` proxy trap either.

> [@robbiespeed](#):
>
> extending a class with a constructor function

I don't see any reason to do that if you can just use `class` syntax instead. But if you're absolutely striving for it, you would write

```javascript
function B() {
  const o = Reflect.construct(A, [], new.target);
  o.z = 3;
  return o;
}
B.prototype = Object.create(A.prototype);

 console.log(new B);

```

---

<div class="post-metadata">

**Author:** ![robbiespeed](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/robbiespeed/32/2544_2.png) [@robbiespeed](https://es.discourse.group/u/robbiespeed)\
**Post date:** [October 21, 2020, 8:14pm UTC](https://es.discourse.group/t/reflect-super/509/3 "2020-10-21T20:14:36Z")

</div>

> [@bergus](#):
>
> it constructs a new object. This is also how a `super()` call works: it asks the parent class to construct a new instance, and then uses that as the `this` value for the current constructor to initialise. There is no `thisArgument` getting passed to the parent constructor.

I understand that is the implementation and thus why `this` cannot be accessed before a call to `super` in the constructor. It's not quite the full picture though, because `super` asks the parent class to construct a new instance **using the child classes prototype, and new.target values**. Which is effectively the same behavior as using `ParentClass.apply(this, args)` minus passing of `new.target` and if `apply` could be used on class constructors.

> [@bergus](#):
>
> Also, `Reflect` is a (admittedly, badly named) namespace for the default implementations of `Proxy` traps, and there is no `super` proxy trap either.

I was not aware there was a tight coupling of the 2, although looking at the APIs of both now I can definitely see it. I guess that raises the question of if a `super` handler for Proxy could be useful. If not would there be a more appropriate location?

> [@bergus](#):
>
> I don't see any reason to do that if you can just use `class` syntax instead.

Indeed there may not be many use cases, but in the cases where you can't use `class` syntax for whatever reason, `Reflect.construct` can work, but it introduces two instances. In your example both `o` and `this` are created. Unless JS engines are optimized to not create `this` if it is not used and there is a object as a return value, but I don't think that's the case since it would be hard to statically determine if the return value was an object.

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [October 21, 2020, 11:31pm UTC](https://es.discourse.group/t/reflect-super/509/4 "2020-10-21T23:31:17Z")

</div>

> [@robbiespeed](#):
>
> `super` asks the parent class to construct a new instance **using the child classes prototype, and new.target values**. Which is effectively the same behavior as using `ParentClass.apply(this, args)` minus passing of `new.target`

Not if the parent class is a builtin such as `Array`, `Function` or `RegExp` that constructs exotic objects. Sure, it does essentially does `Object.setPrototypeOf(…, new.target.prototype)`, but it's still important that the parent class constructs the object itself. A `Reflect.super` call cannot do that.

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [October 26, 2020, 7:11am UTC](https://es.discourse.group/t/reflect-super/509/5 "2020-10-26T07:11:48Z")

</div>

@robbiespeed

```javascript
class A { ... }
class B extends A {
   constructor() {
      super()
      ...
   }
}

```

is roughly the same as

```javascript
function A () {
   if (!new.target) throw new TypeError();
}
function B () {
   if (!new.target) throw new TypeError();
   let _this = Reflect.construct(A, [], new.target);
   ...
   return _this;
}

```

The instance object created for the base, has `new.target.protoype` assigned to it's prototype before the base class constructor even see's the new object. So it's not like using `apply` at all. The onus to create an instance is passed all the way down through the base constructor to the engine, which creates the object and assigns the prototype. Then that object bubbles all the way back up, being initialized by each constructor from base to most derived along the way.
