JavaScript prototype(原型对象)


关键要点

  • 原型对象(prototype)是 JavaScript 实现继承的核心机制,每个函数和对象都有一个原型。
  • 研究表明,原型链允许对象共享属性和方法,优化内存使用。
  • 函数的 prototype 属性定义实例的共享属性,对象的 __proto__ 指向其构造函数的原型。
  • 可通过 Object.create()class 语法实现原型继承,现代开发更推荐 class

原型对象简介

JavaScript 的原型对象(prototype)是其面向对象编程的核心,用于实现继承和属性共享。每个函数都有一个 prototype 属性,指向一个对象,该对象包含所有通过该函数创建的实例共享的属性和方法。每个对象都有一个隐藏的 __proto__ 属性,指向其构造函数的原型对象,从而形成原型链。

基本概念

  • 函数的 prototype:每个函数(如 function Person() {})自动拥有一个 prototype 属性,指向一个对象,包含共享的属性和方法。
  • 对象的 __proto__:每个对象(如 new Person() 的实例)有一个 __proto__ 属性,指向其构造函数的 prototype
  • 原型链:当访问对象的属性或方法时,JavaScript 首先查找对象本身,若未找到,则沿着 __proto__ 查找原型链,直到找到或到达 null

示例:

function Person(name) {
    this.name = name;
}
Person.prototype.sayHello = function() {
    console.log("Hello, " + this.name);
};
var alice = new Person("Alice");
alice.sayHello(); // "Hello, Alice"

详细报告

JavaScript 的原型对象(prototype)是其独特继承机制的核心,允许对象共享属性和方法。本报告基于可靠的中文来源(如 MDN Web Docs、菜鸟教程、W3School)提供全面讲解,涵盖原型的基本概念、原型链、操作方法、继承实现及注意事项。

原型的基本概念

根据 MDN Web Docs: 继承与原型链,JavaScript 是一种基于原型的语言,每个对象都有一个原型对象,属性和方法的查找通过原型链完成。关键点包括:

  • 函数的 prototype 属性:每个函数创建时自动获得一个 prototype 属性,指向一个对象(原型对象)。通过 new 创建的实例共享该原型对象的属性和方法。
  • 对象的 __proto__ 属性:每个对象有一个隐藏的 __proto__ 属性,指向其构造函数的 prototype。注意:__proto__ 是非标准属性,现代推荐使用 Object.getPrototypeOf()
  • 原型链:当访问对象属性时,若对象自身没有该属性,JavaScript 会沿着 __proto__ 查找原型链,直到找到属性或到达 Object.prototype(其 __proto__null)。

示例:

function Person(name) {
    this.name = name;
}
Person.prototype.age = 30;
var alice = new Person("Alice");
console.log(alice.age); // 30(从原型继承)
console.log(alice.__proto__ === Person.prototype); // true

原型链的工作原理

原型链是 JavaScript 实现继承的基础。根据 菜鸟教程: JavaScript 原型(prototype),当访问对象的属性或方法时,查找顺序如下:

  1. 检查对象自身是否有该属性。
  2. 若没有,检查对象的 __proto__(即构造函数的 prototype)。
  3. 若仍未找到,继续沿 __proto__ 查找,直到 Object.prototypenull

示例:

var obj = {};
console.log(obj.toString()); // "[object Object]"(从 Object.prototype 继承)

操作原型的方法

以下是常见操作原型的方法:

  • 添加原型属性/方法
  Person.prototype.sayHello = function() {
      console.log("Hello, " + this.name);
  };
  • 获取原型:使用 Object.getPrototypeOf(obj) 或非标准的 __proto__
  console.log(Object.getPrototypeOf(alice) === Person.prototype); // true
  • 设置原型:使用 Object.setPrototypeOf(obj, prototype)Object.create(prototype)
  var obj = Object.create(Person.prototype);

原型继承的实现

原型继承可以通过以下方式实现:

  1. 通过构造函数和 prototype
   function Animal() {}
   Animal.prototype.speak = function() {
       console.log("Animal speaks");
   };
   function Dog() {}
   Dog.prototype = Object.create(Animal.prototype);
   var dog = new Dog();
   dog.speak(); // "Animal speaks"
  1. 通过 Object.create()
   var animal = { speak: function() { console.log("Animal speaks"); } };
   var dog = Object.create(animal);
   dog.speak(); // "Animal speaks"
  1. 通过 class 语法(ES6 引入):
   class Animal {
       speak() {
           console.log("Animal speaks");
       }
   }
   class Dog extends Animal {}
   var dog = new Dog();
   dog.speak(); // "Animal speaks"

根据 W3School: JavaScript 对象原型class 语法是更现代的方式,底层仍基于原型。

注意事项和最佳实践

  • 性能:频繁修改原型可能影响性能,尤其在大型应用中。建议在初始化时设置原型属性。
  • 避免直接修改内置对象的原型:如 Object.prototypeArray.prototype,可能导致不可预期的行为。
  • 浏览器兼容性__proto__ 是非标准属性,旧浏览器可能不支持;Object.getPrototypeOf()Object.setPrototypeOf() 是标准方法。
  • 内存优化:原型共享属性和方法可减少内存占用,因为实例不需重复存储相同方法。

原型与构造函数的关系

根据 MDN Web Docs,构造函数、原型和实例之间的关系如下:

  • 构造函数(如 Person)的 prototype 属性指向原型对象。
  • 实例(如 alice)的 __proto__ 指向构造函数的 prototype
  • 原型对象的 constructor 属性指向构造函数。

示例:

console.log(Person.prototype.constructor === Person); // true
console.log(alice.__proto__.constructor === Person); // true

总结

JavaScript 的原型对象(prototype)是实现继承和属性共享的核心机制。函数的 prototype 定义共享属性,对象的 __proto__ 连接到原型链,查找属性时沿链向上。开发者可通过构造函数、Object.create()class 实现继承,现代开发推荐使用 class 语法。理解原型机制有助于编写高效、可维护的代码。

关键引用


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注