学习JavaScript类时遇报错:Class constructor Hero cannot be invoked without 'new'
搞定 "Uncaught TypeError: Class constructor Hero cannot be invoked without 'new'" 报错
嘿,这个问题我太熟了!咱们来一步步拆解:
为啥会报错?
核心问题出在ES6类的构造函数规则上——它必须用new关键字调用,绝对不能像普通构造函数那样用call/apply直接执行。你在Mage这个普通函数里写Hero.call(this, name, level),相当于直接把类的构造函数当普通函数来调用,JS引擎直接给你抛出错误,告诉你“这玩意儿必须用new才行”。
而你把Hero改成普通函数构造器时,它本质就是个普通函数,没有这个调用限制,所以call能正常绑定上下文,把父类属性挂载到Mage实例上,自然就不报错了。
正确的解决姿势(ES6类标准写法)
既然用了ES6的class来定义Hero,那继承就用ES6的extends和super就好,这是官方推荐的类继承方式,代码也更清晰:
class Hero { constructor(name, level) { this.name = name this.level = level } greet() { return `${this.name} says hello.` } } // 用extends继承Hero,Mage就成了Hero的子类 class Mage extends Hero { constructor(name, level, spell) { // super必须在this之前调用,用来初始化父类的属性 super(name, level) // 再添加子类自己的属性 this.spell = spell } } // 测试一下 const merlin = new Mage('Merlin', 20, 'Fireball') console.log(merlin.greet()) // 输出 Merlin says hello. console.log(merlin.spell) // 输出 Fireball
非要用函数式构造器配合ES6类?(不推荐,但给个方案)
如果因为某些特殊场景,你必须保留Mage作为普通函数构造器,那可以用Reflect.construct来模拟new的调用过程,绕开类构造函数的调用限制:
class Hero { constructor(name, level) { this.name = name this.level = level } greet() { return `${this.name} says hello.` } } function Mage(name, level, spell) { // 用Reflect.construct调用Hero构造器,同时绑定Mage为实例的原型 const heroInstance = Reflect.construct(Hero, [name, level], Mage) heroInstance.spell = spell return heroInstance } // 测试 const gandalf = new Mage('Gandalf', 30, 'Lightning') console.log(gandalf.greet()) // Gandalf says hello. console.log(gandalf instanceof Hero) // true console.log(gandalf instanceof Mage) // true
不过说实话,这种写法有点绕,除非真的有必要,不然还是用extends的标准写法更省心。
内容的提问来源于stack exchange,提问作者Antonio Pavicevac-Ortiz
相关产品推荐
相关产品推荐

