首页 > 解决方案 > 如何在 ES5 中实现“类扩展”功能(例如装饰器功能),该功能也适用于 ES2015 类

问题描述

我昨天问了一个类似的问题,它被标记为
ES6 的重复:调用类构造函数没有 new 关键字

由于上面链接的文档没有给出完整的答案,我现在问了同样的问题,今天有点不同......并在下面提供了一个可能的解决方案:

我如何必须在以下演示中实现 ES5 函数“扩展”(它应该只是扩展一个类)才能使用 ES2015 类而不会出现“类构造函数 baseClass 不能在没有'new'的情况下被调用”错误?

[编辑:“扩展”函数将成为(转译)ES5 库的一部分。这个库本身以后可能会被使用 ES5 或 >= ES2015 的其他人使用——这两种情况都应该有效]

// 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'

见: https ://jsfiddle.net/kjf7cheo/

一种解决方案可能如下所示(=> 使用“new Function(...)”)。这个解决方案有什么错误/不安全/需要考虑的吗?

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"

标签: javascriptecmascript-6ecmascript-5

解决方案


我会尝试使用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否则原型将会丢失。


推荐阅读