Skip to content

原型链和类继承的区别

1. 原型链(Protrotpye Chain)

核心概念

  • 原型(Prototype):每个 JavaScript 对象(除 null 外)都有一个内部属性 [[Prototype]](可通过 __proto__Object.getPrototypeOf() 访问),指向它的原型对象。
  • 构造函数(Constructor):通过构造函数(普通函数)创建对象时,构造函数的 prototype 属性会成为新对象的原型。
  • 原型链:当访问对象的属性或方法时,如果对象本身没有该属性,JavaScript 会沿着原型链(通过 __proto__)向上查找,直到找到或到达原型链末端(null)。

示例

javascript
// 构造函数
function Person(name) {
  this.name = name;
}

// 在构造函数的原型上添加方法
Person.prototype.sayHello = function() {
  console.log(`Hello, I'm ${this.name}`);
};

// 创建实例
const alice = new Person("Alice");
alice.sayHello(); // 通过原型链找到方法

特点

  • 显式操作原型:需要手动管理原型链(如 Object.create()prototype 属性)。
  • 动态性:原型链是动态的,修改原型会立即影响所有实例。
  • 灵活性:可以灵活地修改或扩展原型链。

2. 类(Class)

核心概念

  • 语法糖:ES6 引入的 class 语法本质上是构造函数和原型链的语法糖,最终仍基于原型链。
  • 类声明:通过 class 关键字定义类,包含构造函数(constructor)、实例方法和静态方法。
  • 继承:通过 extends 实现继承,简化了原型链的继承逻辑。

示例

javascript
class Person {
  constructor(name) {
    this.name = name;
  }

  // 实例方法(添加到原型)
  sayHello() {
    console.log(`Hello, I'm ${this.name}`);
  }

  // 静态方法(直接添加到类本身)
  static staticMethod() {
    console.log("This is a static method");
  }
}

// 继承
class Student extends Person {
  constructor(name, grade) {
    super(name); // 调用父类构造函数
    this.grade = grade;
  }

  study() {
    console.log(`${this.name} is studying`);
  }
}

const bob = new Student("Bob", 10);
bob.sayHello(); // 继承自父类原型

特点

  • 语法简洁:隐藏了原型链的复杂性,代码更易读。
  • 强制使用 new:类必须通过 new 调用,否则报错。
  • 静态方法:通过 static 关键字定义静态方法,直接绑定到类本身。
  • 不可枚举:类中定义的方法默认不可枚举(而原型链中手动添加的方法默认可枚举)。

关键区别

特性原型链(Prototype)类(Class)
语法基于函数和 prototype 属性基于 classconstructorextends 等关键字
继承实现手动设置 prototype__proto__通过 extendssuper 自动处理
方法定义显式添加到原型(如 Person.prototype.fn在类内部直接定义(如 method() {}
静态方法手动添加到构造函数(如 Person.staticFn使用 static 关键字
可枚举性默认可枚举默认不可枚举
调用限制构造函数可不使用 new(但可能导致问题)必须使用 new,否则报错
代码组织松散,依赖约定结构化,更接近传统面向对象语言

为什么说类是语法糖?

类的语法底层仍然基于原型链:

javascript
class Person {}
typeof Person; // "function"(类本质是函数)

// 类的原型机制
console.log(Person.prototype.constructor === Person); // true
const alice = new Person();
console.log(alice.__proto__ === Person.prototype); // true

总结

  • 原型链是 JavaScript 的底层继承机制,灵活但需要手动管理。
  • 是 ES6 引入的语法糖,提供更简洁的语法,但最终仍基于原型链。
  • 适用场景
    • 需要底层控制时使用原型链。
    • 需要代码可读性和结构化时使用类。

理解原型链是掌握 JavaScript 继承机制的核心,而类的语法让代码更符合现代编程习惯。