标准答案
- 原型链:JavaScript 里每个对象都有一个内部原型,可以通过 Object.getPrototypeOf 读取。当访问对象属性时,如果对象自身没有这个属性,引擎会沿内部原型继续查找,直到找到属性或到达 null,这条查找路径就是原型链。
- prototype 与内部原型:函数有 prototype 属性。用 new 调用构造函数时,新对象的内部原型会指向构造函数的 prototype,所以实例可以访问定义在 prototype 上的方法。函数的 prototype 是给实例做原型用的属性;对象的内部原型,也就是 [[Prototype]],才是真正参与属性查找的链接。
- 继承模型:JavaScript 的继承更准确地说是原型委托。ES6 class 和 extends 是基于原型机制的语法糖,不是脱离原型链的新模型。
- 工程实践:共享方法通常放在 prototype 或 class 方法上,避免每个实例重复创建同一份函数。读取原型建议用 Object.getPrototypeOf,尽量不要依赖 __proto__。
题目解析
prototype、__proto__、constructor、class 容易混在一起。可以先讲属性查找,再讲 new 如何连接实例和构造函数 prototype,最后再说 class 只是更清晰的写法。
__proto__ 是历史访问器,不建议作为正式 API 使用。真实代码更推荐 Object.getPrototypeOf 和 Object.setPrototypeOf,但频繁改原型会影响性能。
代码示例
下面例子能说明实例方法查找发生在原型链上。
JavaScript
function User(name) {
this.name = name
}
User.prototype.sayName = function () {
return this.name
}
const user = new User('Alice')
user.sayName() // Alice
Object.getPrototypeOf(user) === User.prototype // true常见误区
- 把 __proto__ 当成推荐 API。实际代码更推荐 Object.getPrototypeOf / Object.setPrototypeOf。
- 误以为 class 脱离了原型链。class 方法仍然定义在原型上。
- 在构造函数内部给每个实例重复创建同一个方法,造成内存浪费。