Reputation: 441
I've asked a similar question yesterday and it was marked as duplicate of
ES6: call class constructor without new keyword
As the above linked document does not give a full answer, I now asked the same question a bit different today ... and provide a possible solution below:
How do I have to implement the ES5 function "extend" (it should just extend a class) in the following demo to also work with ES2015 classes without getting an "Class constructor baseClass cannot be invoked without 'new'" error?
[Edit: The function "extend" will be part of a (transpiled) ES5 library. This library itself may then later be used by someone else who uses either ES5 or >= ES2015 - both cases should work]
// ES5 function (similar to: constr => class extends constr {})
function extend(constr) {
var ret = function () {
constr.apply(null, arguments)
}
ret.prototype = Object.create(constr.prototype)
return ret
}
// ES2015 code
const
baseClass = class {},
extendedClass = extend(baseClass)
new extendedClass() // <- Error: Class constructor baseClass cannot be invoked without 'new'
See: https://jsfiddle.net/kjf7cheo/
One solution could look like follows (=> using "new Function(...)"). Is there anything wrong/insecure/to be considered with this solution?
var extend = null
if (typeof Proxy === 'function') { // check for ECMAScript version >= 2015
try {
extend =
new Function('baseClass', 'return class extends baseClass {}')
} catch (e) {
// ignore
}
}
if (!extend) {
extend = function (baseClass) {
var ret = function () {
baseClass.apply(this, arguments)
}
ret.prototype = Object.create(baseClass.prototype)
return ret
}
}
// Result: function "extend"
Upvotes: 0
Views: 167
Reputation: 441
I think this could be a solution without using "eval(...)" or "new Function(...)" ... what do you think?
Find a demo here: https://jsbin.com/vupefasepa/edit?js,console
var hasReflection =
typeof Reflect === 'object'
&& Reflect
&& typeof Reflect.construct === 'function'
function extend(baseClass) {
var ret = function () {
if (!(this instanceof ret)) {
throw new Error("Class constructor cannot be invoked without 'new'")
}
var type = this.constructor
return hasReflection
? Reflect.construct(baseClass, arguments, type)
: void(baseClass.apply(this, arguments))
}
ret.prototype = Object.create(baseClass.prototype, {
constructor: {
value: ret
}
})
return ret
}
Upvotes: 0
Reputation: 14423
I'd try using Reflect.construct
for this:
let extend = function (constr) {
let ret;
if(Reflect && Reflect.construct){
ret = function(...args){
let inst = Reflect.construct(constr, args, eval('new.target'));
return inst;
}
} else {
ret = function () {
constr.apply(this, arguments)
}
}
ret.prototype = Object.create(constr.prototype);
ret.prototype.constructor = ret;
return ret;
}
The eval
line just makes it so you don't get a syntax error when you transpile it to ES5. It's necessary if you want to extend the constructors you create with extend
otherwise the prototypes will be lost.
Upvotes: 1