The super
call will invoke the Function
constructor, which expects a code string. If you want to access your instance data, you could just hardcode it:
class Smth extends Function {
constructor(x) {
super("return "+JSON.stringify(x)+";");
}
}
but that's not really satisfying. We want to use a closure.
Having the returned function be a closure that can access your instance variables is possible, but not easy. The good thing is that you don't have to call super
if you don't want to - you still can return
arbitrary objects from your ES6 class constructors. In this case, we'd do
class Smth extends Function {
constructor(x) {
// refer to `smth` instead of `this`
function smth() { return x; };
Object.setPrototypeOf(smth, Smth.prototype);
return smth;
}
}
But we can do even better, and abstract this thing out of Smth
:
class ExtensibleFunction extends Function {
constructor(f) {
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class Smth extends ExtensibleFunction {
constructor(x) {
super(function() { return x; }); // closure
// console.log(this); // function() { return x; }
// console.log(this.prototype); // {constructor: …}
}
}
class Anth extends ExtensibleFunction {
constructor(x) {
super(() => { return this.x; }); // arrow function, no prototype object created
this.x = x;
}
}
class Evth extends ExtensibleFunction {
constructor(x) {
super(function f() { return f.x; }); // named function
this.x = x;
}
}
Admittedly, this creates an additional level of indirection in the inheritance chain, but that's not necessarily a bad thing (you can extend it instead of the native Function
). If you want to avoid it, use
function ExtensibleFunction(f) {
return Object.setPrototypeOf(f, new.target.prototype);
}
ExtensibleFunction.prototype = Function.prototype;
but notice that Smth
will not dynamically inherit static Function
properties.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…