在 JavaScript 中,原型(Prototype)、原型链(Prototype Chain)和对象(Object)构成了一种核心的三角关系,它们共同支撑了 JavaScript 的继承机制。理解这三者的关系是掌握 JS 面向对象编程的关键。
 

对象、构造函数、原型三者构成了一个三角关系,核心逻辑如下:

  1. 构造函数与原型

    • 每个构造函数(如 function Person() {})都有一个 prototype 属性,指向其 “原型对象”。
    • 原型对象中有一个 constructor 属性,反向指向其对应的构造函数(Person.prototype.constructor === Person)。
  2. 实例对象与原型

    • 通过构造函数创建的实例对象(如 let p = new Person()),其 __proto__ 属性指向构造函数的原型对象(p.__proto__ === Person.prototype)。
  3. 实例与构造函数

    • 实例对象通过原型链间接关联到构造函数(p.constructor === Person,实际是从原型对象继承的 constructor 属性)。



在这样的描述下你可能觉得云里雾里,没关系我们通过讲故事的方式把他们梳理一遍。

1、什么是对象

首先,你需要明白什么是对象:你可以把对象想象成一个「盒子」,里面装着一些「东西」(属性,比如名字、年龄)和「动作」(方法,比如吃饭、跑步)

比如:

let dog = {
  name: "旺财",  // 属性
  bark: function() { console.log("汪汪!"); }  // 方法
};

这个dog就是一个对象,里面㕛名字和叫的动作。

2. 什么是「原型」?

原型就像对象的「妈妈」,会把自己有的东西(属性 / 方法)「遗传」给孩子。

比如所有的狗都会摇尾巴,但我们没必要给每只狗都写一遍摇尾巴的方法,只需要让「狗妈妈」(原型)会摇尾巴,那么所有小狗(实例对象)就都天生会摇尾巴了。

// 狗妈妈(原型)
let dogPrototype = {
  wagTail: function() { console.log("摇尾巴~"); }
};

// 小狗(实例对象),它的妈妈是 dogPrototype
let dog1 = Object.create(dogPrototype);
let dog2 = Object.create(dogPrototype);

dog1.wagTail();  // 摇尾巴~(从妈妈那继承的)
dog2.wagTail();  // 摇尾巴~(同样从妈妈那来的)

3. 什么是「原型链」?

如果小狗想做一件事,自己不会,就会问妈妈;妈妈不会,就会问外婆;外婆不会,就会问太外婆…… 一直问到「老祖宗」(null)为止。这个「代代相传」的链条就是原型链。

  • 小狗(dog)想 toString()(把自己变成字符串),但它自己不会。
  • 就问妈妈(dogPrototype),妈妈也不会。
  • 妈妈就问外婆(Object.prototype,所有对象的老祖宗之一),外婆会!于是小狗就会了。
console.log(dog1.toString());  // "[object Object]"(从外婆那学的)

4. 三角关系:对象、构造函数、原型

用「生孩子」来比喻:

  • 构造函数 就像「妈妈的肚子」,专门用来「生对象」的(比如 new Person() 生出人对象)。
  • 原型 是「妈妈」,构造函数会把这个「妈妈」指定为所有孩子的原型(Person.prototype 就是人对象的妈妈)。
  • 实例对象 是「孩子」,天生就认这个妈妈(孩子.__proto__ === 妈妈)。

而且:

  • 妈妈(原型)知道自己是哪个肚子生的(妈妈.constructor === 构造函数)。
  • 孩子也知道自己的「出生证明」是哪个构造函数(孩子.constructor === 构造函数,其实是继承了妈妈的记忆)。

让我们举个例子,更深刻的理解

// 1. 构造函数(相当于"生产线",专门用来创建学生对象)
function Student(name) {
  this.name = name; // 每个学生有自己的名字(实例属性)
}

// 2. 原型对象(相当于"共享技能库",所有学生都能共用这里的东西)
Student.prototype = {
  constructor: Student, // 告诉原型:"我属于Student这个构造函数"
  study: function() {    // 所有学生都会学习(共享方法)
    console.log(this.name + "在学习");
  },
  school: "阳光小学"     // 所有学生都在同一所学校(共享属性)
};

// 3. 创建实例对象(用生产线造出两个学生)
let stu1 = new Student("小明");
let stu2 = new Student("小红");


// 现在来看三角关系:

// ① 实例对象 → 原型(学生 → 共享技能库)
console.log(stu1.__proto__ === Student.prototype); // true(小明的技能库是Student原型)
console.log(stu2.__proto__ === Student.prototype); // true(小红的技能库也是Student原型)

// ② 原型 → 构造函数(共享技能库 → 生产线)
console.log(Student.prototype.constructor === Student); // true(技能库属于Student生产线)

// ③ 实例对象 → 构造函数(学生 → 生产线,通过原型间接关联)
console.log(stu1.constructor === Student); // true(小明知道自己来自Student生产线)
console.log(stu2.constructor === Student); // true(小红也知道)


// 再看原型链的作用:

// 学生自己有的属性:直接用
console.log(stu1.name); // "小明"(自己的名字)
console.log(stu2.name); // "小红"(自己的名字)

// 自己没有,但原型有的:从原型拿(共享)
stu1.study(); // "小明在学习"(用原型的study方法)
stu2.study(); // "小红在学习"(用同一个study方法)
console.log(stu1.school); // "阳光小学"(用原型的school属性)

// 原型也没有的:继续往上找(找原型的原型)
console.log(stu1.toString()); // "[object Object]"
// 上面这个方法其实在 Object.prototype 里(所有对象的"老祖宗"原型)
// 查找路径:stu1 → Student.prototype → Object.prototype → 找到toString()

总结:

  • 原型是对象的 “模板”,存储共享属性和方法;
  • 原型链是属性查找的路径,实现了继承;
  • 构造函数、原型、实例三者通过 prototype__proto__constructor 相互关联,形成了 JavaScript 中对象系统的核心三角关系。
Logo

葡萄城是专业的软件开发技术和低代码平台提供商,聚焦软件开发技术,以“赋能开发者”为使命,致力于通过表格控件、低代码和BI等各类软件开发工具和服务

更多推荐