I'd love it if I could make my own class that extended an HTML element class, e.g. HTMLDivElement or HTMLImageElement.
Assuming the standard inheritance pattern:
// class A:
function ClassA(foo) {
this.foo = foo;
}
ClassA.prototype.toString = function() {
return "My foo is " + this.foo;
};
// class B:
function ClassB(foo, bar) {
ClassA.call(this, foo);
this.bar = bar;
}
ClassB.prototype = new ClassA();
ClassB.prototype.toString = function() {
return "My foo/bar is " + this.foo + "/" + this.bar;
};
I'm not able to figure out what to call in the constructor:
function Image2() {
// this doesn't work:
Image2.prototype.constructor.call(this);
// neither does this (only applies to <img>, no equivalent for <span> etc.):
Image.call(this);
}
Image2.prototype = new Image(); // or document.createElement("img");
Image2.prototype.toString = function() {
return "My src is " + this.src;
};
Is this just not possible? Or is there some way? Thanks. =)
Alright, this question needs an update from the current technology.
HTML5 offers ways for you to create custom elements. You need to register your element via document.registerElement
and after that you can use it just like any other tags. The feature is already available in the latest Chrome. I'm not sure about other browsers.
More details here:
http://www.html5rocks.com/en/tutorials/webcomponents/customelements/
I'm not able to figure out what to call in the constructor
Image2.prototype.constructor.call(this);
Yeah, JavaScript's objects don't have classes and chainable constructors like that. It has its own model of prototypes, which can be quite confusing, but doesn't actually deliver the proper potential of prototype inheritance because it's still tied to constructor-functions, which look like class constructors but aren't really.
unfortunately this isn't truly creating a subclass; it's just extending instances in disguise
Yes - that's all JavaScript gives you. If you want to, you can certainly create your own object system that abstracts this away so it seems like you're creating classes and instances. I've attached a flavour I often use at the bottom as an example. But there is no standard for creating a subclass of anything in JavaScript.
For example, in your "standard" code you say:
ClassA.call(this, foo);
but this only works because you have written ClassA in such a way that you can get away with calling it twice, once for the prototype ClassA, with 'foo' set to 'undefined', and then again on the object that inherits from that prototype, to mask that 'foo' behind another 'foo' over the top.
This is not anything actually standard that classes might be expected to do for each other, and it's certainly not specified that this will work for non-JS-native browser objects:
function MyImage() {
Image.call(this); // might do anything. will almost certainly fail
}
MyImage.prototype= new Image();
In any case, setting a prototype to something like an HTMLElement that isn't a native-JavaScript object is not specified by the ECMAScript standard and has varying levels of success; in IE it doesn't work at all, the prototype's properties don't take.
Also,
Image2.prototype.constructor
from your example may actually not be the same as 'Image' as you would expect. 'constructor', apart from being a non-standard property that's not available in all browsers, does something that in a class system would be Not What You Think at all; it is best avoided.
Image2 should have all properties/methods of Image plus more
Currently the only way to do this is with a wrapper of some sort. You can't do this with prototypes for the reasons above; you'd have to add the properties to every instance separately:
function makeImage2() {
var image= Image();
image.isBig= function() {
return this.width>200 || this.height>200;
};
}
this is just a factory function of course, and not anything like subclassing. You would have to provide your own replacement for instanceof.
...
// An example class system
//
Function.prototype.subclass= function() {
var c= new Function(
'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+
'if (arguments[0]!==Function.prototype.subclass._FLAG && this._init) this._init.apply(this, arguments); '
);
if (this!==Object)
c.prototype= new this(Function.prototype.subclass._FLAG);
return c;
};
Function.prototype.subclass._FLAG= {};
// Usage
//
ClassA= Object.subclass();
ClassA.prototype._init= function(foo) {
this.foo= foo;
};
ClassA.prototype.toString= function() {
return 'My foo is '+this.foo;
};
ClassB= ClassA.subclass();
ClassB.prototype._init= function(foo, bar) {
ClassA.prototype._init.call(this, foo);
this.bar= bar;
};
ClassB.prototype.toString= function() {
return ClassA.prototype.toString.call(this)+' and my bar is '+this.bar;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With