I want to do this:
class Parent {
static myMethod1(msg) {
// myMethod2 is undefined
this.constructor.myMethod2(msg);
}
}
class Child extends Parent {
static myMethod2(msg) {
console.log('static', msg);
}
}
Child.myMethod1(1);
But it doesn't work. Is this possible some other way? I don't want to hard code Child.myMethod2 in Parent which I know would work since I want random child classes to be able to define/override the static method but call that method from the parent without prior knowledge of which class is the child.
myMethod2 is undefined because the code is wrong. this is class constructor in static methods, and this.constructor is the constructor of a constructor, i.e. Function. It should be:
class Parent {
static myMethod1(msg) {
this.myMethod2(msg);
}
}
This is antipattern, because Parent doesn't have myMethod2, and Parent.myMethod1() will result in error. It should either contain no-op myMethod2, or be labeled as abstract class to never be accessed directly.
Related
I'd like to use ES6 public class fields:
class Superclass {
constructor() {
// would like to write modular code that applies to all
// subclasses here, or similarly somewhere in Superclass
this.example++; // does NOT WORK (not intialized)
//e.g. doStuffWith(this.fieldTemplates)
}
}
class Subclass extends Superclass {
example = 0
static fieldTemplates = [
Foo,
function() {this.example++},
etc
]
}
Problem:
ES6 public fields are NOT initialized before the constructors, only before the current constructor. For example, when calling super(), any child field will not yet have been defined, like this.example will not yet exist. Static fields will have already been defined. So for example if one were to execute the code function(){this.example++} with .bind as appropriate, called from the superclass constructor, it would fail.
Workaround:
One workaround would be to put all initialization logic after all ES6 public classes have been properly initialized. For example:
class Subclass extends Superclass {
example = 0
lateConstructor = (function(){
this.example++; // works fine
}).bind(this)()
}
What's the solution?
However, this would involve rewriting every single class. I would like something like this by just defining it in the Superclass.constructor, something magic like Object.defineProperty(this, 'lateConstructor', {some magic}) (Object.defineProperty is allegedly internally how es6 static fields are defined, but I see no such explanation how to achieve this programatically in say the mozilla docs; after using Object.getOwnPropertyDescriptor to inspect my above immediately-.binded-and-evaluated cludge I'm inclined to believe there is no way to define a property descriptor as a thunk; the definition is probably executed after returning from super(), that is probably immediately evaluated and assigned to the class like let exampleValue = eval(...); Object.defineProperty(..{value:exampleValue})). Alternatively I could do something horrible like do setTimeout(this.lateConstructor,0) in the Superclass.constructor but that would break many things and not compose well.
I could perhaps try to just use a hierarchy of Objects everywhere instead, but is there some way to implement some global logic for all subclasses in the parent class? Besides making everything lazy with getters? Thanks for any insight.
References:
Run additional action after constructor -- (problems: this requires wrapping all subclasses)
Can I create a thunk to run after the constructor?
No, that is not possible.
How to run code after class fields are initialized, in a sane way?
Put the code in the constructor of the class that defines those fields.
Is there some way to implement some global logic for all subclasses in the parent class?
Yes: define a method. The subclass can call it from its constructor.
Just thought of a workaround (that is hierarchically composable). To answer my own question, in a somewhat unfulfilling way (people should feel free to post better solutions):
// The following illustrates a way to ensure all public class fields have been defined and initialized
// prior to running 'constructor' code. This is achieved by never calling new directly, but instead just
// running Someclass.make(...). All constructor code is instead written in an init(...) function.
class Superclass {
init(opts) { // 'constructor'
this.toRun(); // custom constructor logic example
}
static make() { // the magic that makes everything work
var R = new this();
R.init(...arguments);
return R;
}
}
class Subclass extends Superclass {
subclassValue = 0 // custom public class field example
init(toAdd, opts) { // 'constructor'
// custom constructor logic example
this.subclassValue += toAdd; // may use THIS before super.init
super.init(opts);
// may do stuff afterwards
}
toRun() { // custom public class method example
console.log('.subclassValue = ', this.subclassValue);
}
}
Demo:
> var obj = Subclass.make(1, {});
.subclassValue = 1
> console.log(obj);
Subclass {
subclassValue: 1
__proto__: Superclass
}
I have a custom HTML tag <fancy-foo> that I would like to extend the functionality of. Some of the <fancy-foo> elements would be extended using the pretty-bar custom element, so that I can use them in my HTML as
<fancy-foo is="pretty-bar">
<!-- content -->
</fancy-foo>
so, I define classes FancyFoo and PrettyBar, define the fancy-foo element and extend it using pretty-bar, like so:
class FancyFoo extends HTMLElement {
constructor() {
super();
}
}
class PrettyBar extends FancyFoo {
constructor() {
super();
}
}
window.customElements.define('fancy-foo', FancyFoo);
window.customElements.define('pretty-bar', PrettyBar, {extends: 'fancy-foo'});
Sadly, Google Chrome spits out the error
Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': "fancy-foo" is a valid custom element name
That's an odd error. Strangely, it says "fancy-foo" is a valid custom element name; I know that, but why should that throw an error?
What's going on here?
You cannot extend Custom Elements that way (with {extends: '...'}). You can only extend buit-in (= standard) HTML elements.
If you want to design PrettyBar as an extension of FancyFoo, you'll need to define it as an autonomous custom element:
class PrettyBar extends FancyFoo {...}
window.customElements.define('pretty-bar', PrettyBar)
Same thing for the HTML tag:
<pretty-bar></pretty-bar>
This way it is possible to create correct inheritance chain. Extended built-in element's class is further extensible:
class FancyFoo extends HTMLDivElement {
constructor() {super();}
}
class PrettyBar extends FancyFoo {
constructor() {super();}
}
window.customElements.define('fancy-foo', FancyFoo, {extends: 'div'});
window.customElements.define('pretty-bar', PrettyBar, {extends: 'div'});
<div is="fancy-foo"></div>
<div is="pretty-bar"></div>
customElements.define determines the is-name, constructor, and built-in's tag-name, if used this way. It does not need to know the exact constructor chain, provided it leads to the call of the appropriate built-in's constructor. You can establish the inheritance by extending one class by another.
Style it to override the div behavior, or use a more appropriate built-in element as base.
I want this.method2() call of base to execute base.method2() while it actually executes derived.method2() (I understand the idea behind the behavior), is it possible to achieve this without methods renaming and what is the best practice here?
const base = class {
method() {
this.method2();
}
method2() {
console.error("base.method2");
}
}
const derived = new class extends base {
method() {
super.method();
}
method2() {
console.error("derived.method2");
}
}
derived.method(); // want 'base.method2' here
You can do this with call.
method() {
base.prototype.method2.call(this);
}
In this case you don't technically need to use call and supply the this value, because you don't use it, but it is the best way to create the call you want so it works in all circumstances.
Incidentally, I don't understand what you are seeking to achieve with the const base = class {} statement. A class declaration would be much less surprising: class base {}.
I am new to Dart and I wonder if I can, for example, extend the DivElement class to create custom elements in one line of code. I am looking for something like this;
class RedBox extends DivElement {
RedBox(text) {
this.text = text;
this.style.background = "red";
}
}
RedBox myBox = new RedBox("Hello World");
document.body.append(myBox);
Of course I will have much more complex elements with custom functions. But just in general, is this possible?
When I try to run this, i get:
implicit call to super constructor 'DivElement()'
You can extend HTML elements, but there are a few requirements. The one you're running into now is that you need a RedBox.created constructor, and it can only redirect to its super class. created must be the only generative constructor, though you can add factory constructors.
Another requirement is that the element is registered with document.registerElement.
Try adding this:
class RedBox extends HtmlElement {
RedBox.created() : super.created() {
style.background = "red";
}
factory RedBox(text) => new Element.tag('my-redbox')..text = text;
}
document.registerElement('my-redbox', RedBox);
Some note on extending HtmlElement.
Example:
https://api.dartlang.org/1.14.1/dart-html/HtmlDocument/registerElement.html
Pitfalls:
Extending non HtmlElement(e.g. PreElement) throws:
HierarchyRequestError: Custom element XXX is a native PreElement
should be derived from HtmlElement or SvgElement.
Using extendsTag option with registerElement suppresses the above error but causes "new Element.tag('xxx')" to return an instance of HtmElement.
document.registerElement('xxx', XXX, extendsTag:'pre');
Solution(Assuming extending PreElement):
Use 'document.registerElement('xxx', XXX, extendsTag:'pre');' and 'new Element.tag('pre','xxx');'
void main{
document.registerElement('xxx',
XXX,extendsTag: 'pre');
querySelectior('body').append(new XXX()..text = 'hello');
}
class XXX extends PreElement{
XXX.created():super.created(){}
factory XXX(){
return new Element.tag('pre','xxx');
}
}
Dart does not currently support library initialization. You must call document.registerElement in the main.
Tested with 1.14.0
say, Child class is inheriting Father class and Father class is inheriting spark TextArea class. now from an mxml file (in FLEX4), i am creating multiple objects of Child class. Father class have few static attributes whose values are set by private methods, calling from constructor. Now the question is: all these static attributes are set every time while Child class objects are being created one by one?
If answer is yes then Is it possible that Father class static attributes are set only once and not depends upon the number of Child class objects creation.
Please provide any suggestion or tips
Thanks in advance.
If you are setting static variables from an object's constructor or methods called from the constructor, then yes, they will be set every time. In order to prevent that, just check whether the variable is already set.
public class Foo {
public static var bar:Object;
public Foo(value:Object) {
if (!bar) {
bar = value;
}
}
}
First decide if those static members are really all that important to store as statics because statics are associated with a Class and not an instance it's usually a signal that you're probably doing something you shouldn't if instances are modifying or reading static members. You probably should use a factory method if you need to share that information with the instances. However, if you're sure you should do it then you can use a static initializer block to initialize the members when the class is loaded. Downside is that block throws an exception it can be hard to track down:
public class SomeObject {
private const _someStaticMember : String;
private const _someOtherStaticMember : SomeOtherObject;
static {
_someStaticMember = "foobar";
_someOtherStaticMember = new SomeOtherObject();
}
}