Subclassing Function

# Francisco Tolmasky (10 years ago)

In the existing implementations I’ve tried, it appears I can’t do this:

class SuperFunction extends Function { }

(also tried with constructor(str) { super(str) })

It “works”, but the resulting new SuperFunction("return 5") is just a Function, not a SuperFunction. Is Function meants to be an exception to the subclassing built-ins, or should it also work?

# Allen Wirfs-Brock (10 years ago)

Nope, it's supposed to work. Object.getPrototypeOf(new SuperFunction("") should be SuperFunction.prototype and new SuperFunction("") instanceof SuperFunction should be true.

You need to file a bug report on the implementations where you tried it. Sounds like they still have some work to do

# Erik Arvidsson (10 years ago)
# Jason Orendorff (10 years ago)

On Thu, May 7, 2015 at 3:25 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Nope, it's supposed to work.

Agreed. We're working on it in Firefox. It's of a piece with new.target support, so my best guess is it'll be weeks, maybe a couple months, before it lands in Nightly.

# Nelo Mitranim (9 years ago)

While creating functions from strings is useful, I would much prefer being able to define call and construct methods in the source. Something like:

class SubFunction extends Function {
  // Assigned as internal [[Call]] property.
  [Symbol.functionCall]() {
    return true
  }

  // Optional [[Construct]] override. If included, will be used instead of
  // [[Call]] when called with `new`.
  [Symbol.construct]() {
    // ...
  }
}

const Sub = new SubFunction()
Sub()
new Sub()
# Nelo Mitranim (9 years ago)

On second thought, a construct method wouldn't add anything that classes don't do better. Let's just stick with call:

class SubFunction extends Function {
  someState = {}

  // Assigned as internal [[Call]] property.
  [Symbol.functionCall]() {
    // ...
  }

  someMethod() {
    // ...
  }
}

const sub = new SubFunction()
sub()
# Bradley Meck (9 years ago)

Why not check new.target?

function SubFunction() {
  // function call
  if (new.target === undefined) {
  }
  // constructor call
  else {
  }
}
# Nelo Mitranim (9 years ago)

Separate methods can be decorated. Which raises the question whether the proposal is compatible with decorators in their current state.

# Jordan Harband (9 years ago)

Perhaps you would be interested in the current proposal for Call Constructors tc39/ecma262/blob/master/workingdocs/callconstructor.md ?

# Nelo Mitranim (9 years ago)

@Jordan The linked proposal is what inspired the dual-method part (which I backed away from) of my suggestion.

How we define the call/construct methods of a class is actually orthogonal to how we define the call method of an instance of the hypothetical function subclass. If anything, they have to be keyed separately. Example:

class SubFunction extends Function {
  constructor() {
    // "static" constructor function, sets up instance state
  }

  call constructor() {
    // hypothetical "static function" version of class
  }

  [Symbol.functionCall]() {
    // body of class instance function
  }
}