JS中的类,类的原型,实例三者的异同

185 阅读2分钟

JavaScript 中的类、类的原型和实例的异同

在 JavaScript 中,类(Class)、类的原型(Prototype)和实例(Instance)是面向对象编程的核心概念。下面我将详细解释它们的异同,并提供代码示例。

1. 基本概念

类 (Class)

  • ES6 引入的语法糖,基于原型继承的封装
  • 用于创建对象的模板
  • 包含构造函数和方法的定义

类的原型 (Prototype)

  • 每个 JavaScript 函数(包括类)都有一个 prototype 属性
  • 包含该类的共享方法和属性
  • 实例通过原型链继承这些属性和方法

实例 (Instance)

  • 通过 new 关键字调用类创建的具体对象
  • 每个实例都有自己的属性,但共享原型上的方法

2. 三者的关系

类 (Class) → 类的原型 (Prototype) ← 实例 (Instance)
  • 类定义了如何创建实例
  • 类的原型是所有实例共享的方法和属性的存储位置
  • 实例通过原型链访问原型上的方法和属性

3. 代码示例

// 定义一个类
class Person {
  // 构造函数,用于初始化实例属性
  constructor(name, age) {
    this.name = name; // 实例属性
    this.age = age;   // 实例属性
  }

  // 实例方法(实际上会被添加到Person.prototype上)
  greet() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }

  // 静态方法(属于类本身,不属于实例)
  static species() {
    return 'Homo sapiens';
  }
}

// 1. 类本身
console.log(typeof Person); // "function"(类实际上是函数)
console.log(Person.species()); // "Homo sapiens"(调用静态方法)

// 2. 类的原型
console.log(Person.prototype); // 包含greet方法
console.log(Person.prototype.constructor === Person); // true

// 3. 创建实例
const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);

// 实例访问属性和方法
console.log(person1.name); // "Alice"(实例属性)
person1.greet(); // 调用原型上的方法

// 检查原型链关系
console.log(person1.__proto__ === Person.prototype); // true
console.log(person1 instanceof Person); // true

// 添加方法到原型(会影响所有实例)
Person.prototype.sayGoodbye = function() {
  console.log(`Goodbye from ${this.name}!`);
};

person1.sayGoodbye(); // "Goodbye from Alice!"
person2.sayGoodbye(); // "Goodbye from Bob!"

4. 三者的主要区别

特性类 (Class)类的原型 (Prototype)实例 (Instance)
定义位置使用 class 关键字定义自动创建,通过 ClassName.prototype 访问通过 new ClassName() 创建
包含内容构造函数、静态方法共享的方法和属性实例特有的属性
访问方式直接通过类名访问通过 ClassName.prototypeinstance.__proto__通过变量名访问
是否可被继承是(通过 extends是(通过原型链)
内存中的存在只有一个类定义只有一个原型对象可以有多个实例

5. 更深入的原型链示例

class Animal {
  constructor(name) {
    this.name = name;
  }
  
  eat() {
    console.log(`${this.name} is eating.`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
  
  bark() {
    console.log(`${this.name} is barking!`);
  }
}

const myDog = new Dog('Rex', 'Labrador');

// 原型链关系
console.log(myDog.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true

// 方法查找过程
myDog.eat(); // 先在Dog.prototype找,没有就去Animal.prototype找
myDog.bark(); // 在Dog.prototype找到
myDog.toString(); // 最终在Object.prototype找到

6. 总结

  • 是创建对象的模板,提供了更清晰的语法来创建构造函数和原型
  • 原型是所有实例共享的方法和属性的存储位置,实现了方法的共享和继承
  • 实例是根据类创建的具体对象,拥有自己的属性,但共享原型上的方法

理解这三者的关系对于掌握 JavaScript 的面向对象编程至关重要。原型继承是 JavaScript 的核心特性,即使使用 class 语法,底层仍然是基于原型的实现。