JavaScript prototype(原型对象)

这是测试文本,单击 “编辑” 按钮更改此文本。

JavaScript原型(prototype)详解

JavaScript原型(prototype)详解

面向编程小白的原型对象知识点汇总 – 用大白话解释JavaScript核心概念

什么是原型?

原型的概念

在JavaScript中,每个对象都有一个原型(prototype),原型也是一个对象。

你可以把原型想象成对象的”父母”或”模板”。当你创建一个新对象时,它可以从它的原型那里继承属性和方法

大白话解释:

假设你有一个手机工厂(构造函数):

  • 工厂的设计图纸就是原型(prototype)
  • 按照图纸生产出来的手机就是实例
  • 所有手机都可以使用图纸上定义的功能(方法)

代码示例:

// 构造函数(工厂)
function Phone(model) {
  this.model = model;
}

// 原型(设计图纸)添加方法
Phone.prototype.makeCall = function() {
  console.log(`用${this.model}打电话!`);
};

// 创建实例(生产手机)
const myPhone = new Phone(“iPhone 14”);
myPhone.makeCall(); // 用iPhone 14打电话!
原型链

原型链的概念

原型链是JavaScript实现继承的机制。

当你访问一个对象的属性或方法时:

  1. JavaScript先在对象自身查找
  2. 如果没找到,就去对象的原型上查找
  3. 如果还没找到,就去原型的原型上查找
  4. 直到找到属性或到达原型链顶端(null)

大白话解释:

想象你有一个问题需要解决:

  • 你首先尝试自己解决(对象自身)
  • 自己搞不定就问爸爸(原型)
  • 爸爸搞不定就问爷爷(原型的原型)
  • 直到有人能解决或追溯到祖先尽头

原型链示意图:

实例(myPhone) → 原型(Phone.prototype) → Object.prototype → null

原型链示例:

// 创建一个数组
const arr = [1, 2, 3];

// arr自身没有toString方法
// 查找Array.prototype → 找到toString方法
console.log(arr.toString()); // “1,2,3”

// Array.prototype也没有hasOwnProperty方法
// 继续向上查找Object.prototype → 找到方法
console.log(arr.hasOwnProperty(‘length’)); // true
构造函数

构造函数与原型的关系

在JavaScript中,构造函数是用来创建对象的函数。

每个构造函数都有一个prototype属性,它指向构造函数的原型对象。

当使用new关键字创建实例时:

  • 新对象的内部链接(__proto__)指向构造函数的prototype
  • 因此实例可以访问原型上的属性和方法

代码示例:

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

// 添加到Dog的原型
Dog.prototype.bark = function() {
  console.log(`${this.name}:汪汪!`);
};

const myDog = new Dog(“旺财”);
myDog.bark(); // 旺财:汪汪!

// 检查关系
console.log(myDog.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.constructor === Dog); // true

重要关系图

构造函数(Dog) → prototype属性 → 原型对象(Dog.prototype)
↑                           ↑
|          constructor属性 |
|                           |
实例(myDog) → __proto__属性 → 原型对象(Dog.prototype)
原型继承

如何实现继承?

JavaScript使用原型链实现继承。

实现继承的关键步骤:

  1. 子构造函数调用父构造函数(使用call/apply)
  2. 设置子构造函数的原型为父构造函数的实例
  3. 重置子构造函数原型的constructor属性

继承实现代码:

// 父类
function Animal(name) {
  this.name = name;
}

Animal.prototype.eat = function() {
  console.log(`${this.name}在吃东西。`);
};

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

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

// 修复constructor指向
Cat.prototype.constructor = Cat;

// 添加子类方法
Cat.prototype.meow = function() {
  console.log(`${this.name}:喵喵!`);
};

// 创建实例
const myCat = new Cat(“小花”, “白色”);
myCat.eat(); // 小花在吃东西。
myCat.meow(); // 小花:喵喵!
ES6的class语法

class与原型的关系

ES6引入了class关键字,但它只是原型的语法糖。

class语法更清晰,但底层仍然使用原型机制:

  • class中的constructor对应构造函数
  • class中定义的方法会添加到prototype上
  • extends关键字实现原型继承

class示例:

class Animal {
  constructor(name) {
    this.name = name;
  }

  eat() {
    console.log(`${this.name}在吃东西。`);
  }
}

class Cat extends Animal {
  constructor(name, color) {
    super(name); // 调用父类constructor
    this.color = color;
  }

  meow() {
    console.log(`${this.name}:喵喵!`);
  }
}

const myCat = new Cat(“小花”, “白色”);
myCat.eat(); // 小花在吃东西。
myCat.meow(); // 小花:喵喵!

// 检查原型关系
console.log(myCat instanceof Cat); // true
console.log(myCat instanceof Animal); // true

class语法与传统原型的对比

传统原型 class语法
function Animal() {} class Animal {}
Animal.prototype.eat = function() {} eat() {}
使用call/apply实现继承 使用extends和super
原型使用注意事项

原型修改与性能

原型修改的时机

创建实例前修改原型:

// ✅ 正确做法:先修改原型,再创建实例
Phone.prototype.makeCall = function() {};
const myPhone = new Phone();

// ❌ 避免:创建实例后再添加方法
const myPhone = new Phone();
Phone.prototype.makeCall = function() {}; // 可行但不推荐

原型与性能优化

使用原型的好处:

  • 节省内存 – 方法在原型上只有一份拷贝
  • 动态扩展 – 修改原型会影响所有实例

动态扩展示例:

function Car() {}
const car1 = new Car();
const car2 = new Car();

// 最初没有drive方法
console.log(car1.drive); // undefined

// 在原型上添加方法
Car.prototype.drive = function() {
  console.log(“行驶中…”);
};

// 所有实例都可以访问
car1.drive(); // 行驶中…
car2.drive(); // 行驶中…

原型使用原则

  1. 方法放在原型上(节约内存)
  2. 属性放在构造函数内(每个实例独立)
  3. 避免在原型上存放引用类型值(可能被意外修改)

JavaScript原型总结:理解原型是掌握JavaScript面向对象编程的关键

原型链、构造函数、class语法糖 – 这些概念共同构成了JavaScript的继承体系

发表评论

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

滚动至顶部