js原型链
理解原型链
Js 中的原型链是一个比较有意思的话题,它采用了一套巧妙的方法,解决了 Js 中的继承问题。
按我的理解,原型链可以拆分成:
原型(prototype)
原型(prototype)是一个普通的对象,它为构造函数的实例共享了属性和方法。在所有的实例中,引用到的原型都是同一个对象。
例如:
上面的代码中,我们创建了 2 个 Student 实例,每个实例都有一个 study 方法,用来打印 "study js"。
这样写会有个问题:2 个实例中的 study 方法都是独立的,虽然功能相同,但在系统中占用的是 2 份内存,如果我创建 100 个 Student 实例,就得占用 100 份内存,这样算下去,将会造成大量的内存浪费。
所以 Js 创造了 prototype。
使用 prototype 之后, study 方法存放在 Student 的原型中,内存中只会存放一份,所有 Student 实例都会共享它,内存问题就迎刃而解了。
但这里还存在一个问题。
为什么 student1 能够访问到 Student 原型上的属性和方法?
答案在 proto 中,我们接着往下看。
链(proto)
链(proto)可以理解为一个指针,它是实例对象中的一个属性,指向了构造函数的原型(prototype)。
我们来看一个案例:
从打印结果可以得出:函数实例的 proto 指向了构造函数的 prototype,上文中遗留的问题也就解决了。
但很多同学可能有这个疑问。
为什么调用 student.study 时,访问到的却是 Student.prototype.study 呢?
答案在原型链中,我们接着往下看。
原型链
原型链指的是:一个实例对象,在调用属性或方法时,会依次从实例本身、构造函数原型、构造函数原型的原型... 上去寻找,查看是否有对应的属性或方法。这样的寻找方式就好像一个链条一样,从实例对象,一直找到 Object.prototype ,专业上称之为原型链。
还是来看一个案例:
可以看到, proto 就像一个链一样,串联起了实例对象和原型。
同样,上面代码中还会存在以下疑问。
为什么 Student.prototype.proto 是 Object.prototype?
这里提供一个推导步骤:
先找 proto 前面的对象,也就是 Student.prototype 的构造函数。
1.判断 Student.prototype 类型, typeof Student.prototype 是 object。
2.object 的构造函数是 Object。
3.得出 Student.prototype 的构造函数是 Object。
所以 Student.prototype.proto 是 Object.prototype。
这个推导方法很实用,除了自定义构造函数对象之外,其他对象都可以推导出正确答案。
原型链常见问题
原型链中的问题很多,这里再列举几个常见的问题。
Function.proto 是什么?
找 Function 的构造函数。
判断 Function 类型, typeof Function 是 function。
函数类型的构造函数就是 Function。
得出 Function 的构造函数是 Function。
所以 Function.proto = Function.prototype。
Number.proto 是什么?
这里只是稍微变了一下,很多同学就不知道了,其实和上面的问题是一样的。
找 Number 的构造函数。
判断 Number 类型, typeof Number 是 function。
函数类型的构造函数就是 Function。
得出 Number 的构造函数是 Function。
所以 Number.proto = Function.prototype。
Object.prototype.proto 是什么?
这是个特例,如果按照常理去推导,Object.prototype.proto 是 Object.prototype,但这是不对的,这样下去原型链就在 Object 处无限循环了。
为了解决这个问题,Js 的造物主就直接在规定了 Object.prototype.proto 为 null,打破了原型链的无线循环。
明白了这些问题之后,看一下这张经典的图,我们应该都能理解了。
深入原型链
介绍完传统的原型链判断,我们再从 V8 的层面理解一下。
V8 是怎么创建对象的
Js 代码在执行时,会被 V8 引擎解析,这时 V8 会用不同的模板来处理 Js 中的对象和函数。
例如:
ObjectTemplate 用来创建对象
FunctionTemplate 用来创建函数
PrototypeTemplate 用来创建函数原型
细品一下 V8 中的定义,我们可以得到以下结论。
Js 中的函数都是 FunctionTemplate 创建出来的,返回值的是 FunctionTemplate 实例。
Js 中的对象都是 ObjectTemplate 创建出来的,返回值的是 ObjectTemplate 实例。
Js 中函数的原型(prototype)都是通过 PrototypeTemplate 创建出来的,返回值是 ObjectTemplate 实例。
所以 Js 中的对象的原型可以这样判断:
所有的对象的原型都是 Object.prototype,自定义构造函数的实例除外。
自定义构造函数的实例,它的原型是对应的构造函数原型。
在 Js 中的函数原型判断就更加简单了。
所有的函数原型,都是 Function.prototype。
下图展示了所有的内置构造函数,他们的原型都是 Function.prototype。
看到这里,你是否也可以一看就看出任何对象的原型呢?
附:V8 中的函数解析案例
了解完原型链之后,我们看一下 V8 中的函数解析。
这段代码在 V8 中会这样执行:
以上代码可以分为 5 个步骤:
1.创建函数模板。
2.在函数模板中,拿到函数原型,并赋值。
3.在函数模板中,拿到函数实例,并赋值。
4.返回构造函数。
5.返回构造函数实例。
V8 中的整体执行流程是符合正常预期的,这里了解一下即可。
总结与思考
本文分别从传统 Js 方面、V8 层面组件剖析了原型链的本质,希望大家都能有所收获。
本内容摘抄此大佬的,原网页☞https://mp.weixin.qq.com/s?src=11×tamp=1615097049&ver=2931&signature=Z4UD1QdVTHcIWQ7X9s6UC-xd1cYSofcQYqsOhU1GVcd0icC0m0QevUgs84XFE9J8CvtcT4X1xod9lfXNGx5dUkbJwj7hSVUMEPAvxvbzaI8ULdQzpPl9rRv0ZG9-5S&new=1
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~