在 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 引擎会按照如下顺序查找:
-
自身是否有该属性;
-
没有,就访问
__proto__(即原型); -
再继续访问原型的原型;
-
一直查到
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 对象、继承、类机制、作用域查找等特性的基础。
如果你学到了什么,欢迎点赞收藏 & 关注,我会持续更新更多面向高级前端的底层知识和源码剖析 🙌