17370845950

什么是原型链_JavaScript中原型继承如何实现
JavaScript 采用原型链继承而非类继承,对象通过 proto 链接原型实现属性和方法共享;new 实例时自动赋值 proto = 构造函数.prototype;Object.create() 是安全建立原型链的推荐方式;class 是基于原型链的语法糖;原型链仅影响读取,赋值会遮蔽原型属性。

JavaScript 中没有类继承,只有原型链继承——对象通过 __proto__ 链接到另一个对象(即它的原型),从而共享属性和方法。所谓“原型链”,就是从一个对象出发,沿着 __proto__ 一层层向上查找,直到到达 null 的过程。

为什么 new 一个函数会得到有原型的对象?

因为函数的 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:虽然部分环境支持,但它是非标准、不可靠的写法
  • 若需兼容老环境(如 IE8),应避免 Object.create,改用构造函数 + .prototype 模拟

class 语法糖背后还是原型链吗?

是的。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)的典型表现,也是调试时属性突然不生效的常见原因。