JavaScript面向对象基于原型链,__proto__构成属性查找路径;class是语法糖,本质仍是原型机制;new绑定实例__proto__到构造函数prototype;Object.getPrototypeOf和constructor更可靠。

JavaScript 没有传统类继承的语法糖之前,原型链就是它实现面向对象的唯一底层机制;ES6 的 class 只是语法糖,背后仍是原型链在工作。
原型链的本质是 __proto__ 连接的对象查找路径
每个对象都有一个内部属性 [[Prototype]](可通过 __proto__ 访问),指向它的原型对象;当访问一个属性或方法时,如果当前对象没有,引擎会沿着 __proto__ 一级级向上查找,直到找到或到达 null。
常见错误现象:
- 误以为
obj.__proto__ === Object.prototype总成立 —— 实际上Object.create(null)创建的对象没有原型 - 直接修改
__proto__(如obj.__proto__ = newProto)会影响性能且不推荐,应使用Object.setPrototypeOf()或构造时指定
const parent = { say() { return 'hello'; } };
const child = Object.create(parent);
console.log(child.say()); // 'hello'
console.log(child.__proto__ === parent); // true
new 和构造函数如何触发原型绑定
使用 new 调用函数时,JS 引擎会自动创建空对象,并将其 __proto__ 指向该函数的 prototype 属性所指向的对象。
立即学习“Java免费学习笔记(深入)”;
关键点:
-
Foo.prototype是给实例用的原型,不是Foo自己的原型(Foo.__proto__指向Function.prototype) - 必须通过
new Foo()才能建立这个连接;直接调用Foo()不会设置__proto__ - 若构造函数显式返回对象,则忽略自动创建的对象和原型绑定
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() { return `Hi, ${this.name}`; };
const p = new Person('Alice');
console.log(p.__proto__ === Person.prototype); // true
console.log(p.greet()); // 'Hi, Alice'
class 语法背后的原型操作没变
class 定义的静态方法、实例方法、getter/setter,最终都挂载在 prototype 或构造函数自身上。继承(extends)也只是自动设置了子类的 prototype.__proto__ 和 constructor.__proto__。
容易踩的坑:
-
class A extends B中,A.__proto__ === B成立(静态继承),但A.prototype.__proto__ === B.prototype才是实例原型链的关键 - 箭头函数不会绑定
this,在原型方法中误用会导致丢失实例上下文 -
super()必须在子类构造函数中this使用前调用,否则报错ReferenceError: Must call super constructor
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound`; }
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 必须先调用
this.breed = breed;
}
}
const dog = new Dog('Buddy', 'Golden');
console.log(dog.speak()); // 'Buddy makes a sound'
真正难的不是记住规则,而是调试时能快速判断某个方法到底从哪一层原型来的 —— 多用 Object.getPrototypeOf(obj) 和 obj.constructor 追踪,别只盯着 __proto__ 看。











