原型和它的原型链

简介: 每个函数都有一个自己的prototype属性,默认是一个object空对象(即:函数的原型对象)


网络异常,图片无法展示
|

原型(prototype)


每个函数都有一个自己的prototype属性,默认是一个object空对象(即:函数的原型对象)

网络异常,图片无法展示
|


可以看出此时的object空对象是指内部不存在我们自己添加的属性和方法。原型对象中存在constructor、__proto__属性。


原型对象中constructor指向的是它的函数对象。原型对象、函数对象关系如下:

网络异常,图片无法展示
|

原型添加方法


我们可以给原型对象添加属性或方法,通过实例对象可以直接访问。

function Fun() { }
Fun.prototype.test = function () {
  console.log('test');
}
let f = new Fun()
f.test()

tip: new 一个对象背后做了什么?


创建一个空对象;给对象设置__proto__,值为构造函数对象的prototype属性值(this.__proto__ =Fun.prototype);执行构造函数体,给对象添加属性或方法。


如果直接给函数原型添加方法,函数只能通过prototype访问,调用prototype无意义。

function fun() { }
 fun.prototype.tick = function () {
   console.log('tick');
 }
fun.prototype.tick()


显式原型与隐式原型


显示原型:每个函数都有一个prototype属性。在定义函数时自动添加,默认为object空对象。


隐式原型:每个实例对象都有一个__proto__属性。在创建对象时自动添加,默认指向构造函数的prototype属性值。


所有函数的__proto__都是一样的(函数都是new Function的实例)。

function Fun() { }
let f1 = new Fun()
let f2 = new Fun()
console.log(f1.__proto__ === Fun.prototype); // true
console.log(f2.__proto__ === Fun.prototype); // true

Fun函数在定义时,会自动生成一个原型对象,f1、f2是Fun的实例。

网络异常,图片无法展示
|
Fun函数通过prototype指向自身的原型对象,f1、f2实例通过隐式调用__proto__,指向的是自己构造函数的原型对象。三者其实指向的是同一个地址(原型对象)。

原型对象:相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象。

显式原型与隐式原型关系:


实例.__proto__ === 构造函数.prototype


函数、实例、object关系


首先定义一个函数,函数的prototype属性,指向函数的原型对象。函数的原型对象中的__proto__指向Object的原型对象。


function Fun() { }
let f1 = new Fun()
let f2 = new Fun()


执行上面这段代码,首先会创建一个Object,Object指向自己的函数对象。Object函数对象的prototype指向Object的原型对象。Object的原型对象中包含一些属性方法。比如我们常用的:hasOwnProperty、valueOf、toString等。且Object的原型对象的原型为null。

网络异常,图片无法展示
|

其次,创建函数时,自动创建函数原型对象。函数原型的__proto__指向Object的函数对象。

网络异常,图片无法展示
|

可以通过以下语句可以验证:

console.log(Fun.prototype.__proto__ == Object.prototype);
console.log(f1.__proto__.__proto__ == Object.prototype);

如果上图不能够理解,可以转化成下图:

网络异常,图片无法展示
|


原型链


定义:访问一个对象的属性时,先在自身属性中查找,找到返回;否则再沿着__proto__这条链向上找,找到返回;如果最终没找到,返回undefined


本质:隐式原型链

作用:查找对象的属性(方法)


基础原型链

function Fun() { }
Fun.prototype.test = function () {
  console.log('Fun 中的 test');
}
let f1 = new Fun()
f1.test = function () {
  console.log('f1 实例中的 test');
}
let f2 = new Fun()
f1.test() // f1 实例中的 test
f2.test() // Fun 中的 test
console.log(f1.test2); // undefined
console.log(f1.test2()); // TypeError: f1.test2 is not a function

网络异常,图片无法展示
|

f1实例中存在test方法所以直接使用。


而f2实例中不存在test方法,所以通过原型链(__proto__)向上查找,f2的上一级Fun中存在test方法,所以输出:Fun 中的 test。

f1实例中不存在test2、test2(),对于test2属性输出undefined,对于test2()函数为TypeError。


构造函数、原型、实例对象关系


function fun(){}


上面一行代码就相等于先创建Object、Function,并实例化。再实例化fun函数。 开始加载:


引入Object


网络异常,图片无法展示
|

引入Function

网络异常,图片无法展示
|


至于为什么会多一条隐式原型?


那是因为:所有函数的隐式原型(__proto__)都是一样的(函数就相当于是Function的实例)。所以Function的函数对象的隐式原型指向自身的原型对象。就相当于

Function = new Function();
Function.__proto__ = Function.prototype


Object与Function


Object函数对象,本身就是一个函数。Object函数就相当于是Function的实例。

网络异常,图片无法展示
|

fun执行

网络异常,图片无法展示
|
fun函数就相当于是Function的实例。添加fun的原型指向Function的原型。

网络异常,图片无法展示
|

关系加强版

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


Function原型是一个Object对象,就相当于是Object函数的实例。所以Function原型的隐式原型等于Object的显式原型。


fun函数原型同样是Object对象。

得到关系如下:

网络异常,图片无法展示
|


总结:

  • 函数的显式原型指向的都是默认的Object空对象(原型内部只有constructor和__proto__)。函数的原型对象都是Object实例。但是Object的原型对象为null。Object的原型对象是原型链的尽头。

网络异常,图片无法展示
|

  • 所有函数的隐式原型(__proto__)都是一样的(函数都是new Function的实例),指向Function函数的原型。实例对象的隐式原型等于构造函数的显示原型。

网络异常,图片无法展示
|


原型链继承


基础原型链中讲解了,一个构造函数有多个实例,实例继承了原型上的方法属性。

下面是两个不同的构造函数之间的父子继承。

function Fun1() {
  this.tag = 'div1'
}
Fun1.prototype.test = function () {
  console.log('Fun1 中的 test');
}
function Fun2() { }
Fun2.prototype = new Fun1()
Fun2.prototype.constructor = Fun2
let f2 = new Fun2()
console.log(f2.tag);  // div1
f2.test();  // Fun1 中的 test


两个构造函数之间,Fun2构造函数将原型指向Fun1的实例。在调用Fun2时,Fun2构造函数会通过原型链找到Fun1的原型对象,从而获取原型中的属性或方法。

网络异常,图片无法展示
|


特别要注意的是:我们还需要将Fun2的原型对象指向自身构造函数。如果不指回自身,那么自身的原型属性或方法将失效

网络异常,图片无法展示
|


instanceof


定义:检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

A instanceof B


A:实例。看A的原型链(__proto__

B:构造函数。看B的 prototype 属性。 判断是否正确,只要跟据下图找A、B两个指向是否能够指向同一个。

网络异常,图片无法展示
|

function fun() { }
let f1 = new fun()
console.log(f1 instanceof Fun); // true
console.log(f1 instanceof Object); // true
console.log(Object instanceof Function); // true
console.log(Object instanceof Object); // true
console.log(Function instanceof Function); // true
console.log(Function instanceof Object); // true
console.log(Object instanceof fun); // false


Object instanceof Function。Object为实例,Function为构造函数

网络异常,图片无法展示
|

Object instanceof fun。Object为实例,fun为构造函数。

网络异常,图片无法展示
|

目录
相关文章
|
2天前
|
数据采集 人工智能 自然语言处理
3分钟采集134篇AI文章!深度解析如何通过云无影AgentBay实现25倍并发 + LlamaIndex智能推荐
结合阿里云无影 AgentBay 云端并发采集与 LlamaIndex 智能分析,3分钟高效抓取134篇 AI Agent 文章,实现 AI 推荐、智能问答与知识沉淀,打造从数据获取到价值提炼的完整闭环。
336 90
|
10天前
|
机器人 API 调度
基于 DMS Dify+Notebook+Airflow 实现 Agent 的一站式开发
本文提出“DMS Dify + Notebook + Airflow”三位一体架构,解决 Dify 在代码执行与定时调度上的局限。通过 Notebook 扩展 Python 环境,Airflow实现任务调度,构建可扩展、可运维的企业级智能 Agent 系统,提升大模型应用的工程化能力。
|
人工智能 前端开发 API
前端接入通义千问(Qwen)API:5 分钟实现你的 AI 问答助手
本文介绍如何在5分钟内通过前端接入通义千问(Qwen)API,快速打造一个AI问答助手。涵盖API配置、界面设计、流式响应、历史管理、错误重试等核心功能,并提供安全与性能优化建议,助你轻松集成智能对话能力到前端应用中。
774 154
|
16天前
|
人工智能 数据可视化 Java
Spring AI Alibaba、Dify、LangGraph 与 LangChain 综合对比分析报告
本报告对比Spring AI Alibaba、Dify、LangGraph与LangChain四大AI开发框架,涵盖架构、性能、生态及适用场景。数据截至2025年10月,基于公开资料分析,实际发展可能随技术演进调整。
993 152
|
3天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
2天前
|
数据采集 人工智能 搜索推荐
别再“调教”ChatGPT了!用Qwen2.5打造24小时在线数字分身
在AI时代,专属“数字分身”正从科幻走向现实。依托Qwen2.5-14B大模型、LoRA微调技术及LLaMA-Factory Online平台,仅需四步即可打造会说话、懂风格、能办事的个性化AI助手,让每个人拥有自己的“贾维斯”。
212 152