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
Node.Js Execute System Command Synchronously
How to Duplicate Object Properties in Another Object
JavaScript Calculate the Day of the Year (1 - 366)
How to Filter (Key, Value) with Ng-Repeat in Angularjs
How to Differentiate Single Click Event and Double Click Event
Named Capturing Groups in JavaScript Regex
Get Functions (Methods) of a Class
Are There Pointers in JavaScript
Removeeventlistener on Anonymous Functions in JavaScript
How to Return a List of All the Image File Names from a Folder Using Only JavaScript
JavaScript Convert Hsb/Hsv Color to Rgb Accurately
How to Poll a Google Doc from an Add-On
How to Get the (X, Y) Pixel Coordinates of the Caret in Text Boxes
Swap Rows with Columns (Transposition) of a Matrix in JavaScript
Random Number, Which Is Not Equal to the Previous Number
Why am I Getting a Referenceerror: Abortcontroller Is Not Defined in Discord.Js V13