问题
I was previously rolling my own Javascript OOP but now I'm playing with ES6
and want to use the class defined after definition in a generic way.
Note
Any answer with new
in it is not what I'm after.
Pseudo code:
// base.js
class Base {
constructor(arg) {
this.arg = arg;
}
// This is the behaviour I'm after
//afterDefined(cls) {
afterExtended(cls) { // probably a better name
console.log(`Class name ${cls.prototype.name}`);
}
}
// frombase.js
class FromBase extends Base {
constructor({ p1='val1', p2='val2'} = {}) {
super(...arguments);
this.p1 = p1;
this.p2 = p2;
}
}
The output in the console should be:
'Class name FromBase'
So far the only solution I have come up with is to have a static method on Base
and call it after the class declaration when I define a new class but I will most likely forget to do this more than once.
Just to be really thorough on why I don't like the static solution; it will force me to import Base
in every single file.
Example using a static method (which I don't want) https://jsfiddle.net/nL4atqvm/:
// base.js
class Base {
constructor(arg) {
super(...arguments);
this.arg = arg;
}
// This is the behaviour I'm after
static afterExtended(cls) {
console.log(`Class name ${cls.name}`);
}
}
// frombase.js
class FromBase extends Base {
}
// just after defining the FromBase class
Base.afterExtended(FromBase);
回答1:
There is no javascript built-in trigger that is calling a method on a class when a subclass is defined that extends from it.
Because you're rolling your own library, you could craft some kind of method the creates and returns a new class that extends a given base class. Maybe check out this answer that may help how to define your classes: Instantiate a JavaScript Object Using a String to Define the Class Name
You could also check how other javascript libraries creates (sub)classes. For example, Ext JS has a ClassManager that you could look into.
- http://docs.sencha.com/extjs/6.5.1/classic/Ext.ClassManager.html (docs)
- http://docs.sencha.com/extjs/6.5.1/classic/src/ClassManager.js.html (source)
When this question would be about instantiation and not about defining classes, I would say:
afterDefined(cls) {
console.log(`Class name ${this.constructor.name}`);
}
Usage:
let x = new FromBase()
x.afterDefined() // --> Class name FromBase
To get the name of the class, use
static afterDefined(cls) {
console.log(`Class name ${this.name}`);
}
回答2:
Is this what you're looking for?
class Base {
constructor(arg) { this.arg = arg; }
static afterDefined(cls) {
console.log(`Class name ${this.constructor.name}`);
}
}
Base = new Proxy(Base, {
get: function(target, key, receiver) {
if (typeof target == 'function' && key == 'prototype' && target.name == Base.name) {
Reflect.apply(Base.afterDefined, Reflect.construct(class FromBase {}, []), [])
}
return target[key];
}
});
class FromBase extends Base {}
In order for this to load class names, you will have to embed or forward-declare that information inside of the Proxy receiver
prior to extending from it (which means you either need to enumerate ahead of time which classes you'll be inheriting to or to have some function call just prior to that class's declaration).
There are a bunch of other neat total hacks in the same vein such as looking at the source (text) of the file that you just loaded JavaScript from and then parsing that text as if it were JavaScript (people have used this to write Scheme interpreters that can accept new code inside of <script>
tags).
If you are a library author intending to target Node, there are even more ways to go about doing this.
回答3:
// base.js
class Base {
constructor(arg) {
this.arg = arg;
}
// This is the behaviour I'm after
afterDefined(cls) {
console.log(`Class name ${cls}`);
}
}
// frombase.js
class FromBase extends Base {
constructor(arg) {
super(arg)
}
}
let f = new FromBase();
f.afterDefined('text');//this you text or object
have to be aware of is. file loading order, super
is an instance of the parent class. good luck.
来源:https://stackoverflow.com/questions/45139541/es-6-dynamically-work-on-class-after-definition