ES2015类无法重定义原型?求相关规范文档指引
你观察到的这个差异完全符合ES2015(ES6)的规范要求,并不是实现层面的bug。ES2015类虽然常被称为ES5构造函数+原型继承的“语法糖”,但它在底层机制上做了很多约束,其中就包括对prototype属性的特殊处理。
核心差异的本质
在ES5中,构造函数本质是普通函数,它的prototype是一个可写的数据属性——你可以直接赋值替换整个原型对象,后续通过new创建的实例会自动关联这个新的原型。
但ES2015类的prototype属性是一个访问器属性(accessor property),它的setter被设计为一个空操作:当你尝试给Class.prototype赋值时,这个赋值不会改变类实际使用的原型对象。规范里明确规定,类的原型对象在类定义时就被固定下来,后续的赋值操作只会被静默忽略(如果是严格模式下,还会抛出TypeError)。
规范依据
根据ECMAScript 2015规范的14.5.14 ClassDeclaration Runtime Semantics: Evaluation章节,类在初始化时会通过Object.defineProperty为类本身定义prototype访问器属性:
- getter函数返回类的原型对象(也就是定义类方法时关联的那个对象);
- setter函数是一个空函数,接收赋值的参数但不做任何修改操作。
这就意味着,你对Pet.prototype = {...}的赋值操作根本不会改变类内部使用的原型引用,所以new Pet()创建的实例依然会关联最初的原型对象,调用的还是原来的eat方法。
正确修改类原型的方式
如果你需要调整类的原型方法,不要替换整个prototype对象,而是直接修改现有原型对象的属性:
class Pet { eat() { console.log('Pet is eating ...'); } } // 直接修改现有原型的属性,而非替换整个对象 Pet.prototype.eat = function(){console.log('Pet is REALLY eating ...')}; const pet = new Pet(); pet.eat(); // -> Pet is REALLY eating ...
验证属性特性
你可以通过Object.getOwnPropertyDescriptor直观看到两者的差异:
- ES5构造函数的
prototype是数据属性,writable为true; - ES2015类的
prototype是访问器属性,存在get和set方法,且set方法不会修改原型引用。
内容的提问来源于stack exchange,提问作者jbandi

