JS 原型链
前言
1. 显式原型和隐式原型
prototype: 显式原型- 是构造函数的一个属性, 用于定义实例共享的方法和属性
- 它指向原型对象,该对象上的属性和方法会被实例继承
__proto__: 隐式原型- 是每个对象都有的内部属性
- 它指向创建该对象的构造函数的
prototype,用于建立原型链
构造函数的
prototype和其实例的__proto__指向同一个地方,这个地方叫做原型对象原型对象是实现继承的核心
function Person(name, age) { // 构造函数 |
什么是构造函数
- 可构造函数是可以用
new操作符调用的函数,用于创建对象 - 箭头函数不能作为构造函数
function Person(name, age) { // 这个就是构造函数 |
- 构造函数的
prototype定义实例可以继承的方法 - 实例的
__proto__指向构造函数的prototype
function Person(name, age) { |
2. 构造函数与对象的关系
- 构造函数本质上是函数,用来创建对象。定义构造函数有以下几种常见方式
// 函数声明 |
构造函数与原型的关系
- 每个构造函数的
prototype和其实例的__proto__都指向同一个原型对象 - 同时,所有函数本身都是
Function构造函数的实例
function fn1(name, age) { |
创建对象的方式
在开发中,创建对象有以下几种方式
- 构造函数创建对象: 使用
new调用构造函数创建对象
function Person(name, age) { |
- 字面量创建对象
const person2 = { name: 'abc', age: 10 }; |
new Object创建对象
const person3 = new Object(); |
Object.create创建对象: 创建一个具有指定原型的空对象
const person4 = Object.create({}); |
- 字面量和
new Object创建的对象本质上都是Object构造函数的实例
const person2 = { name: 'abc', age: 10 }; |
Function 和 Object
- 函数是
Function构造函数的实例
function fn() {} |
- 对象是
Object构造函数的实例
const obj = {}; |
- 特殊关系
Object是一个函数,因此它是Function的实例Function本身也是一个函数,因此它是自己的实例
console.log(Function.prototype === Object.__proto__); // true |
3. 原型链的起点与终点
原型的本质
Person.prototype是构造函数Person的原型对象Function.prototype是构造函数Function的原型对象- 所有的原型对象都是对象,因此本质上它们是通过
new Object()创建的
function Person() {} |
Person.prototype和Function.prototype都是Object构造函数的实例- 因此,它们的
__proto__都指向Object.prototype
什么是原型链
- 原型链是通过
__proto__属性连接起来的对象链 - 当访问一个对象的属性时,如果该对象没有这个属性,会通过
__proto__向上查找,直到null为止

原型链的终点
- 原型链的终点是
null,这是JavaScript中的对象链的终止点 - 任何对象的
__proto__最终都会指向Object.prototype,而Object.prototype.__proto__ === null

4. 原型链的实际应用
原型继承的机制
- 原型继承允许实例对象使用构造函数原型对象上的方法或属性
- 实例对象会通过
__proto__链接到构造函数的prototype,实现属性和方法的继承
function Person(name) { // 构造函数 |
person实例对象的__proto__指向Person.prototype- 调用
person.sayName()时,JavaScript引擎会通过__proto__查找到原型对象上的sayName方法

属性查找规则
- 优先查找实例对象本身的属性
- 如果实例对象中没有该属性,会沿着原型链向上查找,直到
null - 如果在原型链中也未找到,返回
undefined
function Animal(type) { |
5. 原型链核心机制
instanceof
- 原理: 判断
B.prototype是否在对象A的原型链上。 instanceof通过检查A.__proto__是否等于B.prototype,如果不等则沿着原型链向上查找,直到找到匹配或到达null。
A instanceof B |
function Person(name) { |
结果分析
Person instanceof Function → true
Person 是函数,函数是 Function 的实例
原型链:Person.proto === Function.prototypePerson instanceof Object → true
所有对象(包括函数)最终继承自 Object
原型链:Person.proto.proto === Object.prototypeperson instanceof Person → true
person 是 Person 的实例
原型链:person.proto === Person.prototypeperson instanceof Object → true
所有实例对象最终继承自 Object
原型链:person.proto.proto === Object.prototype
自定义实现instanceof
- 以下是
instanceof的核心逻辑,用递归实现
function myInstanceof(A, B) { |
constructor
constructor是对象的一个属性,指向创建该对象的构造函数- 原型与构造函数的互指关系
- 构造函数的
prototype对象有一个constructor属性,指向该构造函数本身
- 构造函数的
function Fn() {} |
- 实例访问
constructor- 实例对象通过
__proto__继承prototype,因此可以访问constructor
- 实例对象通过
const instance = new Fn(); |
Fn.prototype.constructor → Fn |
原型链练习
原型链练习#1
var F = function() {}; |
答案
f.a(); // 输出 'a' |
原型链
- f 的原型链:f.proto → F.prototype → Object.prototype → null
- F 的原型链:F.proto → Function.prototype → Object.prototype → null
关键点
- f 是实例对象,只能访问 Object.prototype
- F 是函数对象,既能访问 Function.prototype 也能访问 Object.prototype
原型链练习 #2
var A = function() {}; |
答案
console.log(b.n); // 1 |
关键点
重新赋值 A.prototype 不会影响已创建的实例
- b 创建时:b.proto → 旧原型 {n: 1}
- A.prototype 重新赋值:A.prototype → 新原型 {n: 2, m: 3}
- c 创建时:c.proto → 新原型 {n: 2, m: 3}
原型链状态
b.__proto__ → {n: 1} (旧原型) |
原型链练习 #3
var foo = {}, |
答案
console.log(foo.a); // 'value a' |
关键点
- foo 是普通对象,只能访问 Object.prototype
- F 是函数对象,既能访问 Function.prototype 也能访问 Object.prototype
原型链
foo.__proto__ → Object.prototype → null |
原型链练习#4
function A() {} |
答案
console.log(new A().a); // 1 |
关键点
实例自身的属性优先于原型链上的属性
- new A().a → 构造函数未设置 a,从原型链获取 → 1
- new B().a → 构造函数设置了 this.a = undefined,实例自身有 a 属性 → undefined
- new C(2).a → 构造函数设置了 this.a = 2,实例自身有 a 属性 → 2
原型链练习 #5
console.log(123['toString'].length + 123); // ? |
答案
console.log(123['toString'].length + 123); // 124 |
关键点
- 数字 123 包装为 Number 对象
- 沿原型链找到 Number.prototype.toString
- toString.length 为 1(表示接受 1 个可选参数 radix)
- 1 + 123 = 124




