JavaScript类中__proto__去向?类继承原型疑问
JavaScript类继承原型链的常见误区
一、搞混了「类本身的__proto__」和「实例的__proto__」
你在资料里看到的ChildClass.__proto__ === ParentClass,说的是子类构造函数自身的原型指向父类构造函数,不是类的实例。直接测试这个场景就对了:
console.log(extraThing.__proto__ === thing); // 输出 true
这个设计是为了让子类能继承父类的静态方法。
而你打印的thing1.__proto__、thing2.__proto__是实例的原型,它们分别指向各自类的prototype对象:
console.log(thing1.__proto__ === thing.prototype); // true console.log(thing2.__proto__ === extraThing.prototype); // true
二、父类方法在原型链的下一层
子类实例能调用父类的doAThing,是因为子类的prototype的原型指向父类的prototype:
console.log(extraThing.prototype.__proto__ === thing.prototype); // true
Object.getOwnPropertyNames()只会获取对象自身拥有的属性,不会遍历原型链,所以你看不到父类的方法。要查看原型链上的所有属性,可以写个遍历函数:
function getAllProps(obj) { const propSet = new Set(); let current = obj; while (current) { Object.getOwnPropertyNames(current).forEach(p => propSet.add(p)); current = Object.getPrototypeOf(current); } return [...propSet]; } console.log(getAllProps(thing2.__proto__)); // 输出 ["constructor", "doAnotherThing", "doAThing"]
或者直接调用验证:
thing2.doAThing(); // 正常输出 "Doing a very cpu heavy thing."
这说明父类方法确实在原型链上,只是Object.getOwnPropertyNames没帮你往上查找。
三、[[IsClassConstructor]]隐藏属性的实际影响
除了限制必须用new调用,它还有几个关键作用:
- 类的prototype.constructor不可枚举:普通构造函数的
prototype.constructor是可枚举的,类的则不是,所以Object.keys()拿不到,但Object.getOwnPropertyNames可以获取。 - 类定义的方法默认不可枚举:比如
doAThing这种类方法,默认不会出现在for...in循环或Object.keys()结果里,而普通构造函数原型上的方法是可枚举的。 - 返回值处理规则:如果类构造函数返回原始值(数字、字符串、null等),会直接忽略这个返回值,返回
new创建的实例;如果返回对象,就会返回这个对象,但这个对象的原型不会自动绑定到类的prototype(和普通构造函数一致),不过一般不会这么写,会破坏继承链。
四、完整原型链梳理
最后把整个继承链路理清楚:
extraThing.__proto__ → thing:子类构造函数继承父类构造函数,用于静态方法继承extraThing.prototype.__proto__ → thing.prototype:子类原型继承父类原型,用于实例方法继承thing2.__proto__ → extraThing.prototype:实例的原型指向自身类的原型thing2.__proto__.__proto__ → thing.prototype:实例通过原型链访问父类方法
内容的提问来源于stack exchange,提问作者krembo master
相关产品推荐
相关产品推荐

