跳转到内容

JavaScript原型链

来自代码酷


JavaScript原型链是JavaScript中实现继承的核心机制,它允许对象通过内部Prototype属性访问其他对象的属性和方法。理解原型链对于掌握JavaScript面向对象编程至关重要。

基本概念[编辑 | 编辑源代码]

在JavaScript中,每个对象(除null外)都有一个原型对象(prototype),对象会从其原型继承属性和方法。当访问对象的属性时,如果对象本身没有该属性,JavaScript会沿着原型链向上查找,直到找到该属性或到达原型链末端(null)。

原型对象[编辑 | 编辑源代码]

每个函数都有一个prototype属性(构造函数的原型),而每个对象都有一个内部Prototype属性(可通过Object.getPrototypeOf()__proto__访问)。

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

// 为Person的原型添加方法
Person.prototype.greet = function() {
  return `Hello, my name is ${this.name}`;
};

const alice = new Person('Alice');
console.log(alice.greet()); // 输出: "Hello, my name is Alice"

原型链图示[编辑 | 编辑源代码]

graph LR A[alice实例] -->|[[Prototype]]| B[Person.prototype] B -->|[[Prototype]]| C[Object.prototype] C -->|[[Prototype]]| D[null]

原型链的工作原理[编辑 | 编辑源代码]

当访问对象属性时,JavaScript引擎会执行以下步骤:

  1. 检查对象自身是否拥有该属性
  2. 如果没有,检查对象的Prototype
  3. 重复此过程直到找到属性或到达null

属性查找示例[编辑 | 编辑源代码]

const parent = { a: 1 };
const child = { b: 2 };
Object.setPrototypeOf(child, parent); // 设置原型

console.log(child.a); // 输出: 1 (通过原型链找到)
console.log(child.b); // 输出: 2 (自身属性)
console.log(child.c); // 输出: undefined (未找到)

原型继承[编辑 | 编辑源代码]

JavaScript使用原型链实现继承。ES6的class语法是原型继承的语法糖。

继承实现示例[编辑 | 编辑源代码]

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

Animal.prototype.speak = function() {
  return `${this.name} makes a noise`;
};

function Dog(name) {
  Animal.call(this, name); // 调用父类构造函数
}

// 设置原型链
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.speak = function() {
  return `${this.name} barks`;
};

const dog = new Dog('Rex');
console.log(dog.speak()); // 输出: "Rex barks"

原型链相关方法[编辑 | 编辑源代码]

Object.create()[编辑 | 编辑源代码]

创建一个新对象,使用现有对象作为新对象的原型。

const proto = { x: 10 };
const obj = Object.create(proto);
console.log(obj.x); // 输出: 10

Object.getPrototypeOf()[编辑 | 编辑源代码]

获取对象的原型。

const arr = [];
console.log(Object.getPrototypeOf(arr) === Array.prototype); // 输出: true

instanceof 操作符[编辑 | 编辑源代码]

检查构造函数的prototype是否出现在对象的原型链中。

console.log([] instanceof Array); // 输出: true
console.log([] instanceof Object); // 输出: true

实际应用案例[编辑 | 编辑源代码]

方法共享[编辑 | 编辑源代码]

原型链允许所有实例共享方法,节省内存。

function Car(model) {
  this.model = model;
}

// 所有Car实例共享同一个drive方法
Car.prototype.drive = function() {
  return `${this.model} is driving`;
};

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

扩展内置对象[编辑 | 编辑源代码]

通过修改原型可以扩展内置对象功能(需谨慎)。

Array.prototype.last = function() {
  return this[this.length - 1];
};

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

性能考虑[编辑 | 编辑源代码]

  • 原型链过长会影响查找性能
  • 在对象上直接定义常用属性比通过原型链访问更快
  • 现代JavaScript引擎优化了原型链查找

常见误区[编辑 | 编辑源代码]

1. 混淆__proto__prototype

  * prototype是函数属性
  * __proto__是实例属性(已废弃,建议使用Object.getPrototypeOf()

2. 直接修改内置对象原型:可能导致不可预期的行为

3. 忘记设置constructor:在继承时需要正确设置constructor属性

数学表示[编辑 | 编辑源代码]

原型链可以表示为属性查找函数:

GetProperty(obj,prop)={obj[prop]如果 obj 有 prop 属性GetProperty(proto,prop)其中 proto = Object.getPrototypeOf(obj)undefined如果 proto 为 null

总结[编辑 | 编辑源代码]

JavaScript原型链是:

  • 基于原型的继承系统
  • 所有对象通过Prototype链接
  • 属性查找沿链向上进行
  • 构造函数通过prototype属性设置实例原型
  • ES6类语法是原型继承的语法糖

理解原型链是掌握JavaScript面向对象编程的关键,它解释了JavaScript中对象如何共享和继承行为。