返回

在 JavaScript 中深入理解原型和原型链

前端

在 JavaScript 中,原型是一个关键概念,它为对象提供了继承和共享功能的机制。为了全面了解原型及其在代码中的运作方式,让我们深入探究原型和原型链的世界。

原型的概念

JavaScript 中的每个对象都拥有一个隐式属性 __proto__,该属性指向其构造函数的原型对象。原型是一个特殊对象,它充当对象的蓝图,为对象提供属性和方法。

function Person(name) {
  this.name = name;
}

const person1 = new Person("John");
console.log(person1.__proto__); // Output: {constructor: ƒ, name: "..."}

在上面的示例中,person1__proto__ 属性指向 Person 函数的原型对象。此原型对象包含 constructor 属性,它指向 Person 构造函数,以及其他属性,如 name

原型链

每个对象的 __proto__ 属性都指向其构造函数的原型对象,而该原型对象的 __proto__ 属性又指向其构造函数的原型对象,如此依次类推,形成了一条链状结构,称为原型链。

function Parent() {}
function Child() {}
Child.prototype = new Parent();

const child1 = new Child();
console.log(child1.__proto__.__proto__); // Output: {constructor: ƒ}

在这个示例中,child1__proto__ 属性指向 Child 构造函数的原型对象,而 Child 构造函数的原型对象的 __proto__ 属性指向 Parent 构造函数的原型对象。

继承和属性查找

原型链在继承和属性查找中发挥着至关重要的作用。当对象尝试访问不存在的属性时,JavaScript 会沿着原型链向上查找,直到找到该属性或达到 null。这允许子对象继承父对象的属性和方法,而无需显式复制它们。

function Animal() {}
Animal.prototype.type = "Animal";

function Dog() {}
Dog.prototype = new Animal();
Dog.prototype.breed = "German Shepherd";

const dog1 = new Dog();
console.log(dog1.type); // Output: "Animal"
console.log(dog1.breed); // Output: "German Shepherd"

重写和扩展原型

虽然子对象从父对象继承属性和方法,但子对象可以重写这些属性和方法,从而覆盖父对象的实现。此外,子对象的原型对象可以扩展,添加新的属性和方法。

function Person() {}
Person.prototype.greet = function() {
  console.log("Hello!");
};

function Employee() {}
Employee.prototype = new Person();
Employee.prototype.greet = function() {
  console.log("Welcome to the company!");
};

const employee1 = new Employee();
employee1.greet(); // Output: "Welcome to the company!"

总结

原型和原型链是 JavaScript 中强大的机制,它们提供了对象继承和属性查找的灵活方式。通过了解这些概念,开发人员可以创建可重用、可扩展的代码,从而提高代码的效率和维护性。