Javascript 如何在ES5中实现同样适用于ES2015类的“类扩展”函数(例如decorator函数)
我昨天问了一个类似的问题,它被标记为 由于上面的链接文件没有给出完整的答案,我今天问的同样的问题有点不同。。。并提供以下可能的解决方案: 我必须如何实现ES5函数extend它应该在下面的演示中扩展一个类,以便在不获取类构造函数的情况下也使用ES2015类baseClass不能在没有“new”错误的情况下调用 [编辑:函数extend将是传输的ES5库的一部分。该库本身随后可能会被使用ES5或>=ES2015的其他人使用-这两种情况都可以使用]Javascript 如何在ES5中实现同样适用于ES2015类的“类扩展”函数(例如decorator函数),javascript,ecmascript-6,ecmascript-5,Javascript,Ecmascript 6,Ecmascript 5,我昨天问了一个类似的问题,它被标记为 由于上面的链接文件没有给出完整的答案,我今天问的同样的问题有点不同。。。并提供以下可能的解决方案: 我必须如何实现ES5函数extend它应该在下面的演示中扩展一个类,以便在不获取类构造函数的情况下也使用ES2015类baseClass不能在没有“new”错误的情况下调用 [编辑:函数extend将是传输的ES5库的一部分。该库本身随后可能会被使用ES5或>=ES2015的其他人使用-这两种情况都可以使用] // ES5 function (similar
// 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'
我会尝试使用Reflect.construct:
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;
}
eval行只是使它在传输到ES5时不会出现语法错误。如果你想扩展你用extend创建的构造函数,这是必要的,否则原型就会丢失。我认为这可能是一个不使用eval的解决方案。。。或新功能。。。你觉得怎么样 请在此处查找演示:
如果您已经在处理类,为什么要混合构造函数类型?上面的代码将是transpiled ES5库的一部分。这个库以后可能会被其他使用ES5或>=ES2015I的人使用我不明白这有什么区别?如果您使用的是transpiler,那么您可以创建类;如果您没有使用transpiler,那么它就不会是ES5环境,因为您有类。除非您想使用它来扩展传输的代码?让我们假设库中有一个函数decoratebaseClass,该函数在内部使用extend,可以用作ES2015 decorateclass{…}或ES5 decoratesMees5constructor,这两个函数都可以用于您的答案。这个解决方案的问题是,对以下代码的输出将是false而不是true:类A{};常数B=extendA;console.lognew B instanceofB@MinusFor:我想它一定是Reflect.construct,args,在上面的代码片段中派生出来的,然后它似乎可以工作,对吗?@Natasha噢,我用错了,它需要一个类似数组的对象,而不是散播参数。注意,您确实需要new.target,这样您就可以正确地设置原型了。。。但是,对于ES5来说,这不是有效的语法。你可以把它包在评估线上though@MinusFor谢谢,您的最新版本=>eval'new.target'运行良好。但是现在我们有一个问题,使用eval是不好的,甚至比使用新函数更糟糕。。。正如我在上面的解决方案中所做的那样。你知道如何用其他东西来替换eval'new.target'吗?我想这个.constructor在这种情况下可以工作,我现在想不出一个edge案例,但它似乎可以工作。
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;
}
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
}