Is there any way to inherit a class from JS native function?
For example, I have a JS function like this:
function Xarray()
{
Array.apply(this, a
In your case, a good bet would be to use this pattern:
function XArray(array) {
array = array || [];
//add a new method
array.second = function second() {
return array[1];
};
//overwrite an existing method with a super type pattern
var _push = array.push;
array.push = function push() {
_push.apply(array, arguments);
console.log("pushed: ", arguments);
};
//The important line.
return array
}
Then you can do:
var list = XArray([3, 4]);
list.second() ; => 4
list[1] = 5;
list.second() ; => 5
note however that:
list.constructor ; => Array and not XArray
Constructors that return an object implicitly substitute the value of this
for callers of super()
. Generated constructor code has to capture whatever super()
returns and replace it with this
.
Built-in classes use ES6 new.target
to do the fixup but there's no way for ES5 code to ensure that new.target has a value calling the constructor.
This is why your extra methods vanish - your object has the wrong prototype.
All you need to do is fix the prototype chain after calling super()
.
export class RoleSet extends Array {
constructor() {
super();
Object.setPrototypeOf(this, RoleSet.prototype);
}
private containsRoleset(roleset:RoleSet){
if (this.length < roleset.length) return false;
for (var i = 0; i < roleset.length; i++) {
if (this.indexOf(roleset[i]) === -1) return false;
}
return true;
}
public contains(item: string | RoleSet): boolean {
if (item) {
return typeof item === "string" ?
this.indexOf(item) !== -1 :
this.containsRoleset(item);
} else {
return true;
}
}
}
Be aware that this curse shall afflict thy children and thy children's children until the end of code; you have to do the fixup in every generation of an inheritance chain.
With purpose to overcome the problem of extension of the native Array class, I took advantage of a decorator.
function extendArray(constructor: Function) {
Object.getOwnPropertyNames(constructor.prototype)
.filter(name => name !== 'constructor')
.forEach(name => {
const attributes = Object.getOwnPropertyDescriptor(constructor.prototype, name);
Object.defineProperty(Array.prototype, name, attributes);
});
}
@extendArray
export class Collection<T> extends Array<T> {
constructor(...args: T[]) {
super(...args);
}
// my appended methods
}
BTW This decorator can be made more generic (for other native classes) if to use a decorator factory.
Don't know how frowned upon this is but for example I needed to create an array of BulletTypes so that I could cycle through them. What I did is the following:
interface BulletTypesArray extends Array<BulletType> {
DefaultBullet?: Bullet;
}
var BulletTypes: BulletTypesArray = [ GreenBullet, RedBullet ];
BulletTypes.DefaultBullet = GreenBullet;
Obviously you could could also make a generic interface, something like interface SuperArray<T> extends Array<T>
.