彻底搞懂 JavaScript 原型与原型链

66 阅读2分钟

在 JavaScript 中,“原型”与“原型链”是理解面向对象编程、继承机制、类的本质等核心知识的基础。本文将以实例+图示+源码视角,彻底帮你吃透原型机制。

一、什么是原型(Prototype)

在 JavaScript 中,每一个对象都有一个隐藏属性 [[Prototype]],通过 __proto__ 访问,它指向一个对象,这个对象就称为它的原型

构造函数(函数类型)则有一个显式的 prototype 属性,它在创建实例时用于设置实例的原型。

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

const p1 = new Person('Alice');

console.log(p1.__proto__ === Person.prototype); // ✅ true

二、proto 与 prototype 的区别

属性属于含义举例
prototype构造函数用于指定实例的原型对象Person.prototype
__proto__实例对象实例的原型对象p1.__proto__ === Person.prototype

注意:__proto__非标准但实际可用的浏览器属性,标准中使用 Object.getPrototypeOf(obj) 来获取原型。

三、什么是原型链

当我们访问一个对象的属性时,JavaScript 引擎会按照如下顺序查找:

  1. 自身是否有该属性;

  2. 没有,就访问 __proto__(即原型);

  3. 再继续访问原型的原型;

  4. 一直查到 null,结束查找。

这条从对象出发,一层一层向上查找原型的路径,就叫做 原型链(Prototype Chain)

🌐 示例:

const arr = [];

console.log(arr.toString); // 来自 Array.prototype
console.log(arr.hasOwnProperty); // 来自 Object.prototype

四、构造函数、实例、原型的关系图

构造函数(Function) 
    |
    |.prototype
    ↓
原型对象(Function.prototype)
    ↑
    |.__proto__
实例对象(new Function()) → __proto__ → Function.prototype
function A() {}
const a = new A();

console.log(a.__proto__ === A.prototype); // ✅
console.log(A.prototype.constructor === A); // ✅

五、深入理解 class 与原型

class 本质上是 function 的语法糖,它依然使用 prototype 来实现继承。

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

  sayHi() {
    console.log(`Hi, I'm ${this.name}`);
  }
}

console.log(typeof Person); // 'function'
console.log(Person.prototype.constructor === Person); // true

❗重点理解:

  • Person.prototype 是实例对象的原型;

  • Person 本身是一个函数,它的原型是 Function.prototype

  • 实例通过 __proto__ 链接到 Person.prototype

六、Function 和 Object 的“互咬”关系

JavaScript 中有一个非常有趣的结构,即:

console.log(Function instanceof Object); // true
console.log(Object instanceof Function); // true

这是因为:

  • Function.__proto__ === Function.prototype

  • Object.__proto__ === Function.prototype

  • Function.prototype.__proto__ === Object.prototype

这形成了一种“鸡生蛋,蛋生鸡”的双向结构:

Function  --> Function.prototype --> Object.prototype --> null
Object    --> Function.prototype --> Object.prototype --> null

七、常见面试题 & 易错点整理

Function.prototype === MyClass.prototype 吗?

class MyClass {}

console.log(Function.prototype === MyClass.prototype); // ❌ false
  • Function.prototype 是类本身的原型(MyClass 的 __proto__

  • MyClass.prototype 是实例的原型(实例对象的 __proto__

Object.getPrototypeOf(fn) 等于什么?

function fn() {}

console.log(Object.getPrototypeOf(fn) === Function.prototype); // ✅ true

八、手写 instanceof 的原理

function myInstanceof(obj, constructor) {
  let proto = Object.getPrototypeOf(obj);
  while (proto) {
    if (proto === constructor.prototype) return true;
    proto = Object.getPrototypeOf(proto);
  }
  return false;
}

📌 九、原型链终点:null

console.log(Object.getPrototypeOf(Object.prototype)); // null

所有原型链最终都会走到 Object.prototype,它的原型是 null

口诀:

构造函数有 prototype,实例通过 __proto__ 链接,查属性靠原型链,终点是 null,切记别混淆!

最后

理解原型和原型链不仅是 JS 面试高频点,也是我们深入理解 JS 对象、继承、类机制、作用域查找等特性的基础。

如果你学到了什么,欢迎点赞收藏 & 关注,我会持续更新更多面向高级前端的底层知识和源码剖析 🙌