JavaScript 原型与原型链的特点,使用场景及案例

在 JavaScript 中,原型(prototype)原型链(prototype chain) 是核心的概念,它们是 JavaScript 实现继承的基础。下面将详细解释这些概念、它们的特点、使用场景及案例。


1. 原型(Prototype)

概念:
  • 每个 JavaScript 对象 (包括函数)都有一个隐藏的内部属性叫做 [[Prototype]],这个属性指向另一个对象,这个对象就是它的原型
  • 当你创建一个对象时,该对象会从它的原型对象继承属性和方法。构造函数创建的每个对象实例都有一个隐式的原型引用。
关键点:
  • 所有的 JavaScript 对象都有原型,除了一些特殊情况(如 Object.prototype 的原型是 null)。
  • 原型是用来实现对象属性和方法共享的机制。通过原型,多个对象可以共享相同的属性和方法,节省内存。
  • 通过 constructor.prototype 可以访问构造函数的原型对象。
案例:
javascript 复制代码
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

// 实例对象 john 的原型指向 Person.prototype
console.log(john.__proto__ === Person.prototype); // true

在这个例子中,Person 构造函数的所有实例(如 john)都共享 greet 方法,因为它们的原型对象是 Person.prototype


2. 原型链(Prototype Chain)

概念:
  • 原型链 是指对象通过其 [[Prototype]] 属性(也可以通过 __proto__ 访问)一层一层地向上查找属性和方法,直到找到或到达 null 终止搜索的过程。
  • 当访问一个对象的属性或方法时,如果该对象自身没有这个属性或方法,JavaScript 引擎会沿着原型链向上查找。
关键点:
  • 原型链是实现继承的基础,通过原型链,JavaScript 的对象可以继承属性和方法。
  • 原型链的终点是 Object.prototype,它的 [[Prototype]]null,表示原型链的结束。
  • 如果原型链中没有找到所需的属性或方法,JavaScript 会返回 undefined
案例:
javascript 复制代码
function Animal() {
  this.species = 'Animal';
}

Animal.prototype.move = function() {
  console.log('Animal is moving');
};

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

// Dog 继承自 Animal
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

const dog = new Dog('Rex');
console.log(dog.name);   // Rex
dog.move();              // Animal is moving

// 原型链:dog --> Dog.prototype --> Animal.prototype --> Object.prototype --> null
console.log(dog.__proto__ === Dog.prototype);           // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true

在这个例子中,dog 实例没有 move 方法,但通过原型链,它从 Animal.prototype 中继承了 move 方法。


3. 特点与使用场景

3.1 原型(Prototype)的特点
  • 共享属性和方法:通过原型对象,多个实例对象可以共享相同的方法和属性。这在节省内存方面很有效,尤其是在创建大量对象时。

  • 动态修改:你可以在程序运行时动态修改原型对象,比如添加新的方法或属性,这些修改会立即影响到所有实例。

  • 内置对象的原型 :JavaScript 的内置对象(如 ArrayStringFunction)也有原型,可以通过修改这些原型来影响内置对象的行为。

3.2 原型链(Prototype Chain)的特点
  • 继承机制:原型链是 JavaScript 实现继承的核心机制。子对象可以通过原型链继承父对象的属性和方法。

  • 原型链的查找过程 :当访问对象的属性或方法时,JavaScript 会首先检查对象自身的属性和方法,如果没有找到,会沿着原型链逐层向上查找,直到找到或者到达 null

  • 性能考虑:虽然原型链机制简化了继承,但过长的原型链可能导致性能问题,因为每次访问属性时都要逐层查找。


4. 原型与原型链的实际使用场景

4.1 使用场景:共享方法

通过将方法定义在构造函数的原型对象上,可以在所有实例之间共享这些方法,从而减少内存消耗。

javascript 复制代码
function Car(make, model) {
  this.make = make;
  this.model = model;
}

// 在原型上定义方法
Car.prototype.start = function() {
  console.log(`${this.make} ${this.model} is starting`);
};

const car1 = new Car('Toyota', 'Corolla');
const car2 = new Car('Honda', 'Civic');

car1.start(); // Toyota Corolla is starting
car2.start(); // Honda Civic is starting

console.log(car1.start === car2.start); // true

这里,car1car2 实例共享了同一个 start 方法,避免了重复定义。

4.2 使用场景:继承和原型链

当创建复杂的类层次结构时,可以利用原型链来实现继承,子类继承父类的属性和方法。

javascript 复制代码
function Mammal(name) {
  this.name = name;
}

Mammal.prototype.speak = function() {
  console.log(`${this.name} makes a sound`);
};

function Cat(name) {
  Mammal.call(this, name); // 继承父类的属性
}

Cat.prototype = Object.create(Mammal.prototype); // 继承父类的方法
Cat.prototype.constructor = Cat;

const kitty = new Cat('Kitty');
kitty.speak(); // Kitty makes a sound

Cat 继承了 Mammalspeak 方法,同时通过 Mammal.call(this, name) 来继承 Mammal 的属性。

4.3 使用场景:扩展内置对象

通过扩展 JavaScript 内置对象的原型,可以给内置对象添加新的功能或方法。

javascript 复制代码
// 给 Array 添加一个新方法
Array.prototype.last = function() {
  return this[this.length - 1];
};

const arr = [1, 2, 3];
console.log(arr.last()); // 输出 3

在这个例子中,我们给 Array 原型添加了一个 last 方法,所有的数组对象都可以直接使用它。


5. 原型与原型链的总结

  • 原型 是每个对象(特别是函数的实例对象)都具有的一个属性,指向另一个对象。通过这个属性,JavaScript 对象可以共享属性和方法。

  • 原型链 是多个对象之间的层级关系,体现了对象从另一个对象继承属性和方法的机制。对象在访问某个属性时,会沿着原型链逐层查找,直到找到为止。

  • 使用原型和原型链的场景 通常包括创建大量对象时为了减少内存开销而共享方法、实现继承机制以及扩展内置对象的功能。

掌握原型和原型链的原理,是理解 JavaScript 对象模型及其继承机制的关键。

相关推荐
远望清一色5 分钟前
基于MATLAB边缘检测博文
开发语言·算法·matlab
何曾参静谧13 分钟前
「Py」Python基础篇 之 Python都可以做哪些自动化?
开发语言·python·自动化
Prejudices17 分钟前
C++如何调用Python脚本
开发语言·c++·python
我狠狠地刷刷刷刷刷30 分钟前
中文分词模拟器
开发语言·python·算法
wyh要好好学习33 分钟前
C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中
开发语言·c#·wpf
AitTech33 分钟前
C#实现:电脑系统信息的全面获取与监控
开发语言·c#
qing_04060336 分钟前
C++——多态
开发语言·c++·多态
孙同学_36 分钟前
【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”
开发语言·c++
还是大剑师兰特37 分钟前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
froginwe1137 分钟前
XML 编辑器:功能、选择与使用技巧
开发语言