理解 JavaScript 中的原型继承:初学者指南

JavaScript 是一种功能强大的动态语言,具有面向对象编程 (OOP) 范式。与许多其他 OOP 语言(如 Java 或 C++)不同,JavaScript 不使用传统继承。相反,它采用原型继承,既灵活又独特。

在这篇博客中,我们将深入探讨原型继承的概念,探索其工作原理,并查看实际示例以更好地理解其功能。

**什么是原型继承?**

原型继承允许 JavaScript 对象通过原型链共享属性和方法。每个 JavaScript 对象都有一个指向另一个对象的内部链接,称为其原型。如果在对象本身上找不到属性或方法,JavaScript 会在原型链中查找它。

这种机制允许对象从其他对象“继承”行为,使其成为 JavaScript 面向对象特性的基石。

**关键术语**

1.原型:

另一个对象继承其属性的对象。

2.**原型**:

对对象原型的内部引用(或链接)。

3.对象.原型:

所有 JavaScript 对象间接继承的顶级原型。

4.原型链:

JavaScript 遍历原型的层次结构来查找属性或方法。

**原型继承如何发挥作用?**

下面是一个示例,用于说明原型继承的实际应用:

// Define a base object
const animal = {
  eats: true,
  walk() {
    console.log("Animal walks");
  },
};

// Create a new object that inherits from 'animal'
const dog = Object.create(animal);
dog.barks = true;

console.log(dog.eats); // true (inherited from animal)
dog.walk(); // "Animal walks" (method inherited from animal)

console.log(dog.barks); // true (own property)

**解释**

  • 狗对象使用 Object.create() 方法从动物对象继承属性和方法。
  • 当访问 dog.eats 时,JavaScript 首先检查 eats 属性是否直接存在于 dog 上。如果不存在,它会在 animal 原型中查找该属性。
  • **创建原型**

    Object.create() 是建立原型继承的最简单方法。

    const vehicle = {
      wheels: 4,
      drive() {
        console.log("Vehicle drives");
      },
    };
    
    const car = Object.create(vehicle);
    console.log(car.wheels); // 4
    car.drive(); // "Vehicle drives"

    在引入 ES6 类之前,构造函数是创建具有继承的对象的主要方式。

    function Person(name) {
      this.name = name;
    }
    
    Person.prototype.greet = function () {
      console.log(`Hello, my name is ${this.name}`);
    };
    
    const john = new Person("John");
    john.greet(); // "Hello, my name is John"

    这里,Person 构造函数使用 Person.prototype 设置原型。通过 new Person() 创建的对象继承了 Person.prototype 上定义的方法。

    ES6 引入了类语法,使得继承更加直观,同时仍然利用底层的原型链。

    class Animal {
      constructor(name) {
        this.name = name;
      }
    
      speak() {
        console.log(`${this.name} makes a noise`);
      }
    }
    
    class Dog extends Animal {
      speak() {
        console.log(`${this.name} barks`);
      }
    }
    
    const dog = new Dog("Buddy");
    dog.speak(); // "Buddy barks"

    尽管这看起来像经典继承,但它仍然基于 JavaScript 的原型继承。

    **原型链实际应用**

    让我们直观地看一下原型链的工作原理:

    const parent = {
      greet() {
        console.log("Hello from parent");
      },
    };
    
    const child = Object.create(parent);
    
    child.sayHi = function () {
      console.log("Hi from child");
    };
    
    child.greet(); // "Hello from parent"

    原型链:

  • 子对象:sayHi()
  • 父对象(原型):greet()
  • Object.prototype(基本原型):类似 toString() 的方法
  • 如果在其中任何一个中都找不到方法或属性,JavaScript 将返回未定义。

    **原型继承的好处**

    1.内存效率:

    共享方法和属性存储在原型上,不会在实例之间重复。

    2.动态继承:

    您可以在运行时修改原型,并且所有继承对象都会反映该变化。

    3.结构灵活:

    对象可以直接从其他对象继承而不需要严格的类层次结构。

    **限制**

    1.原型链性能:

    长原型链会减慢属性查找的速度。

    2.初学者的困惑:

    理解**proto**、prototype 和 Object.create() 可能会很困难。

    3.缺乏私有字段:

    在 ES6 之前,私有属性很难使用原型实现。

    **结论**

    原型继承是 JavaScript OOP 模型的基石,可提供灵活性和动态行为。无论您使用的是 Object.create()、构造函数还是 ES6 类,了解原型链都是编写有效且高效的 JavaScript 代码的关键。

    有了这些知识,您现在可以探索高级主题,如混合、原型操作以及经典继承和原型继承之间的区别。

    祝你编码愉快!🚀