How to Extend Function with Es6 Classes

ES6/ES7 extend functions and export extended

extends keyword applies to classes, not functions. While in your original code the object definition is syntactically a function, if you want to adapt this code to the ES6 standards, you'd have to switch to class syntax.

Basically:

class Tween {
constructor(...args) {
// whatever you want on instantiation
}

start() {
// whatever it does
}
}
...
class TweenExtended extends Tween {
constructor(...args) {
super(...args) // this calls the constructor of Tween
// any additional initialization you want
}

stop() {
// you can override the Tween method or leave it be
}

start() {
// you can any new methods you want
}
}

and then just

export default TweenExtended

or

export TweenExtended

I hope this helps.

Extending Built-in Array With ES6 Classes - Method is not a function error

UPDATED ANSWER

To answer your modified question, TypeScript doesn't let you extend built-ins like Array, Error etc. The reason is written here.

In ES2015, constructors which return an object implicitly substitute
the value of this for any callers of super(...). It is necessary for
generated constructor code to capture any potential return value of
super(...) and replace it with this.

As a result, subclassing Error, Array, and others may no longer work
as expected. This is due to the fact that constructor functions for
Error, Array, and the like use ECMAScript 6's new.target to adjust the
prototype chain; however, there is no way to ensure a value for
new.target when invoking a constructor in ECMAScript 5. Other
downlevel compilers generally have the same limitation by default.

So if you must extend built-in Array under ES5 environment, then you can try Babel for compiling your code. However be aware that it has it's limitation as stated here.

Built-in classes such as Date, Array, DOM etc cannot be properly
subclassed due to limitations in ES5 (for the transform-classes
plugin). You can try to use babel-plugin-transform-builtin-extend
based on Object.setPrototypeOf and Reflect.construct, but it also has
some limitations.

OLD ANSWER

While the code itself is perfectly find and also executes fine in the browser, I think the error you are getting is because of the TypeScript compiler.

For the source code

interface Animal {
name: string;
weight: number
}

class AnimalCollection extends Array <Animal> {
constructor(name: string, ...items: Animal[]) {
super(...items);

Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: name
})
}

findAnimal(name:string): Animal | null {
return this.find(a => a.name === name) || null;
}
}

const animalsArray = [
{name: 'TD-23', weight: 60},
{name: 'TD-25', weight: 50},
{name: 'TXD-26', weight: 120},
{name: 'TYD-26', weight: 40}
];

const animals = new AnimalCollection('Deers', ...animalsArray)

console.log(animals.findAnimal('TD-23'));

If the compiler target option is set to ES5, then it produces code that breaks the implementation. The code it generates is

"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var AnimalCollection = /** @class */ (function (_super) {
__extends(AnimalCollection, _super);
function AnimalCollection(name) {
var items = [];
for (var _i = 1; _i < arguments.length; _i++) {
items[_i - 1] = arguments[_i];
}
var _this = _super.apply(this, items) || this;
Object.defineProperty(_this, 'name', {
enumerable: false,
writable: false,
value: name
});
return _this;
}
AnimalCollection.prototype.findAnimal = function (name) {
return this.find(function (a) { return a.name === name; }) || null;
};
return AnimalCollection;
}(Array));
var animalsArray = [
{ name: 'TD-23', weight: 60 },
{ name: 'TD-25', weight: 50 },
{ name: 'TXD-26', weight: 120 },
{ name: 'TYD-26', weight: 40 }
];
var animals = new (AnimalCollection.bind.apply(AnimalCollection, __spreadArrays([void 0, 'Deers'], animalsArray)))();
console.log(animals.findAnimal('TD-23'));

However, if we set the target in tsconfig.json to something equal to or greater than ES2015, then the code it generates is

"use strict";
class AnimalCollection extends Array {
constructor(name, ...items) {
super(...items);
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: name
});
}
findAnimal(name) {
return this.find(a => a.name === name) || null;
}
}
const animalsArray = [
{ name: 'TD-23', weight: 60 },
{ name: 'TD-25', weight: 50 },
{ name: 'TXD-26', weight: 120 },
{ name: 'TYD-26', weight: 40 }
];
const animals = new AnimalCollection('Deers', ...animalsArray);
console.log(animals.findAnimal('TD-23'));

Which of course works. So I think there is an issue in TypeScript compiler for version ES5 or less, which breaks the implementation. I have tried using Babel for compilation and it works for ES5.

How to extend object with ES6 class instance properties and methods

No, this does not work with class syntax. It's a bit more than just syntactic sugar. The prototypical inheritance stayed the same, but the initialisation of instances works differently now especially for inherited classes, and you cannot invoke a constructor without new to not create a new instance.

I would recommend to be explicit about your mixin, and give it an init method:

class Mixin {
constructor(methods) {
this.descriptors = Object.getOwnPropertyDescriptors(methods);
}
extend(object) {
for (const p in this.descriptors)) {
if (Object.prototype.hasOwnProperty.call(object, p)) {
if (process.env.NODE_ENV !== 'production') {
console.warn(`Object already has property "${p}"`);
}
} else {
Object.defineProperty(object, p, this.descriptors[p]);
}
}
}
}
// define a mixin:
const xy = new Mixin({
initXY() {
this.someProperty= {};
},
someMethod() { … }
});
// and use it:
class ClassName {
constructor() {
this.initXY();
}
}
xy.extend(ClassName.prototype);

How to dynamically extend ES5 and ES6 classes

Your usage of Object.create to overwrite the .prototype with a new object could as easily be

Object.defineProperties(klass.prototype, modifiedDescriptors)

that keeps the object the same but changes its properties.

Extending parent class methods in child class in Javascript ES6

You can use super in methods:

doSomething(e) {
super.doSomething(e)
console.log('doing another something', e)
}

this in child class and in parent class is the same thing, and refers to the actual object, so if you call a method in parent's code, it will call child's implementation, if it is indeed a child. Same works in other languages, for example Python and Ruby.

Working code:

class Parent {  constructor(elem) {    this.elem = elem    this.elem.addEventListener('click', (e) => { this.doSomething(e) })  }
doSomething(e) { alert('doing something') }}
class Child extends Parent { constructor(elem) { super(elem) }
doSomething(e) { super.doSomething(e) alert('doing another something') }}
let child = new Child(document.getElementById('button'))
<button id="button">Alert</button>

Define a class that extends Function

I'm not 100% what you're trying to do, but in order to correctly extend a class in ES6 you must called super() before you do anything.

class Foo extends Function {

constructor(){
super();
this.x = 'foo';
}

}

let test= new Foo();
console.log(test.x); // 'foo'

You can try it out on the babel REPL here

How do I extend an ES6 class with ES5?

Answering this myself:

class A {
constructor() {}
}

function B() {
Object.assign(this, new A());
}
B.prototype = Object.create(A.prototype);

Not sure if there are any side-effects here or not



Related Topics



Leave a reply



Submit