JavaScript 采用原型链继承而非类继承,对象通过 proto 链接原型实现属性和方法共享;new 实例时自动赋值 proto = 构造函数.prototype;Object.create() 是安全建立原型链的推荐方式;class 是基于原型链的语法糖;原型链仅影响读取,赋值会遮蔽原型属性。
JavaScript 中没有类继承,只有原型链继承——对象通过 __proto__ 链接到另一个对象(即它的原型),从而共享属性和方法。所谓“原型链”,就是从一个对象出发,沿着 __proto__ 一层层向上查找,直到到达 null 的过程。
因为函数的 prototype 属性会被自动赋给实例的 __proto__。这个机制是原型链继承的起点。
function Person(name) { this.name = name; } 定义后,Person.prototype 默认是一个空对象,且自带 constructor 指向 Person
const p = new Person('Alice') 创建实例时,引擎自动执行 p.__proto__ = Person.prototype
p.toString() 的调用,实际是沿 p.__proto__ → Person.prototype.__proto__ → Object.prototype 查找,最终落到 Object.prototype.toString
用 Object.setPrototypeOf() 或直接赋值 __proto__(不推荐)可显式设置原型,但更常见、更安全的是用 Object.create()。
const animal = {
eats: true,
walk() { console.log('walking'); }
};
const rabbit = Object.create(animal);
rabbit.jumps = true;
console.log(rabbit.eats); // true ← 来自 animal
rabbit.walk(); // 'walking' ← 来自 animal
Object.create(animal) 创建的新对象,其 __proto__ 直接指向 animal
{}.__proto__ = animal:虽然部分环境支持,但它是非标准、不可靠的写法Object.create,改用构造函数 + .prototype 模拟是的。class 只是语法糖,所有行为仍基于原型链,包括 extends、静态方法、super 调用。
立即学习“Java免费学习笔记(深入)”;
class Animal {
constructor(name) { this.name = name; }
speak() { console.log(`${this.name} makes a sound`); }
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() { console.log('Woof!'); }
}
const d = new Dog('Max', 'Golden');
d.speak(); // 'Max makes a sound'
d.bark(); // 'Woof!'
console.log(d.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
Dog.prototype.__proto__ 指向 Animal.prototype,构成链式继承Dog.create())挂在 Dog 函数本身上,不参与实例原型链super 在方法中实际访问的是 this.__proto__.__proto__ 对应的方法(严格说是 [[HomeObject]] 决定的,但效果等价)
真正容易被忽略的是:原型链只影响「读取」,赋值操作永远作用于当前对象自身。比如 d.eats = false 不会修改 Animal.prototype.eats,而是在 d 上新建一个同名自有属性——这是原型链“遮蔽”(shadowing)的典型表现,也是调试时属性突然不生效的常见原因。