原型链详解「2」

本文详细讲解原型链,介绍了`__proto__`和`prototype`。`__proto__`指向构造函数的原型对象,原型链通过它实现,实例查找属性时会沿其向上找。`prototype`可定义公共方法和值,用于实现继承。还阐述了Object和Function的关系,二者都是函数对象。

原型链详解

proto和prototype

什么是proto,proto在上一篇文章曾讲到过,任何对象都具有一个proto属性,这个属性指向其构造函数的原型对象,函数的_proto_指向Function的prototype对象,下面我们来验证一下,先创建一个构造函数

	function Person(){}
    Person.prototype.name = 'John'
    Person.prototype.age = 25
    Person.prototype.sex = '男'
    Person.prototype.sayName = function(){
      console.log(this.name)
    }
    let p1 = new Person()

对象p1带有一个_proto_属性,创建它的构造函数是Person,那么proto指向的就是Person的原型对象,即:
p1._proto_ == Person.prototype
没有图是没有说服力的,下面请看图:
在这里插入图片描述
根据上面这个图,我们能得到:

Person.prototype.constructor == Person
p1._proto_ == Person.prototype
p1.constructor == Person

当我们打印p1的时候发现它只是一个空对象,并没有constructor属性,但是当我们打印p1.constructor的时候却能真实的返回它的构造函数,这是为什么呢?这里就是通过_proto_来实现的,先声明一下:实例的_proto_属性和构造函数是没有直接关系的,它只和构造函数的prototype存在着联系,这里就充分的体现出了_proto_的作用了,当从实例中去拿一个方法的时候,如果实例不存在,就会通过_proto_属性查找其构造函数的原型对象上是否存在改属性,如果有就会拿过来使用,如果没有,则会继续向上寻找,直到寻找到Object的原型对象上才会停下来,因为Object.prototype._proto_ == null代表着原型链的尽头,下面我们来使用代码展示一下:

   function Person(){}
   Person.prototype.name = 'John'
   Person.prototype.age = 25
   Person.prototype.sex = '男'
   Person.prototype.sayName = function(){
     console.log(this.name)
   }
   let p1 = new Person();
   let p2 = new Person();
   p1.name = 'hjx'
   console.log(p1.name) //hjx
   console.log(p2.name) //John

这里就充分的体现出了原型链这个概念,创建一个构造函数Person,在构造函数的原型对象上定义它的属性,然后创建两个Person的实例p1和p2,当我们打印p1和p2的name属性的时候,打印出的结果却不相同,这是因为在打印p1的那么属性之前我们给实例p1添加了一个name属性,按照原型链的概念,当实例中存在这个属性就会直接拿过来用的原则自然而然就会打印出‘hjx’,因为p1和p2是两个不同的地址,p2中没有name属性,那么他会按照原型链的原则去它构造函数的原型对象上拿取name属性,如果没有则会继续向上查找,直到原型链的尽头位置,在这里构造函数Person的原型对象上定义了name这个属性,所以会打印出Jhon,
所以,原型链是通过_proto_属性来实现的,而并非prototype,那么prototype是用来做什么的呢?
上面已经讲述过了,实例的proto属性指向的是其构造函数的原型对象,也就是构造函数的prototype,所以,我们可以通过prototype来进行公共方法的定义,和公共值得定义,换句话来说,可以通过原型链来实现继承,在继承中,prototype扮演着一个很重要的角色。

Object和Function的关系

我们都知道Object和Function都是函数对象

console.log(typeof Object) //function
console.log(typeof Function) //function

Object是通过new Function()创建的,本文开篇提到过,所有的函数对象的_proto_都指向Function.prototype,所以Object._proto_ == Function.prototype因为Function也是函数对象,所以Function._proto_ == Function.prototype,因为Function的构造函数指向的是它本身。
还有一个等式也是成立的,就是Function.prototype._proto_ == Object.prototype个人认为因为Function.prototype._proto_指向本身的构造函数的原型对象无限循环并没有什么意义,为了能让原型链顺利结束,所以会指向给Object.prototype,可以通过控制台打印一个obj来进行验证,这里就不做验证了。

标题基于SpringBoot的马术俱乐部管理系统设计与实现AI更换标题第1章引言介绍马术俱乐部管理系统的研究背景、意义、国内外研究现状、论文方法及创新点。1.1研究背景与意义阐述马术俱乐部管理系统对提升俱乐部管理效率的重要性。1.2国内外研究现状分析国内外马术俱乐部管理系统的发展现状及存在的问题。1.3研究方法以及创新点概述本文采用的研究方法,包括SpringBoot框架的应用,以及系统的创新点。第2章相关理论总结和评述与马术俱乐部管理系统相关的现有理论。2.1SpringBoot框架理论介绍SpringBoot框架的基本原理、特点及其在Web开发中的应用。2.2数据库设计理论阐述数据库设计的基本原则、方法以及在管理系统中的应用。2.3马术俱乐部管理理论概述马术俱乐部管理的基本理论,包括会员管理、课程安排等。第3章系统设计详细描述马术俱乐部管理系统的设计方案,包括架构设计、功能模块设计等。3.1系统架构设计给出系统的整体架构,包括前端、后端和数据库的交互方式。3.2功能模块设计详细介绍系统的各个功能模块,如会员管理、课程管理、预约管理等。3.3数据库设计阐述数据库的设计方案,包括表结构、字段设计以及数据关系。第4章系统实现介绍马术俱乐部管理系统的实现过程,包括开发环境、编码实现等。4.1开发环境搭建介绍系统开发所需的环境,包括操作系统、开发工具等。4.2编码实现详细介绍系统各个功能模块的编码实现过程。4.3系统测试与调试阐述系统的测试方法、测试用例以及调试过程。第5章系统应用与分析呈现马术俱乐部管理系统的应用效果,并进行性能分析。5.1系统应用情况介绍系统在马术俱乐部中的实际应用情况。5.2系统性能分析从响应时间、并发处理能力等方面对系统性能进行分析。5.3用户反馈与改进收集用户反馈,提出系统改进建议。第6章结论与展望总结马术俱乐部管理系统的设计与实现成果,并展望未来的研究
<think>嗯,用户想了解JavaScript中的原型和原型链,我得先理清楚这些概念。首先,原型是什么?根据引用[5],每个函数都有一个prototype属性,指向原型对象,这个对象里的属性和方法可以被所有实例共享。比如Person构造函数,它的prototype添加了name和sayName方法,这样所有实例比如person1和person2都能调用这个方法,而且方法是同一个,节省内存。 接下来原型链呢?引用[2]提到每个对象都有一个内部属性(__proto__)指向原型对象,形成链式结构。比如实例person1的__proto__指向Person.prototype,而Person.prototype本身也是个对象,它的__proto__又指向Object.prototype,这样一层层直到null,形成原型链。当访问对象的属性时,如果自身没有,就会沿着原型链向上查找,直到找到或到顶层。 继承方面,引用[3]和[4]都提到基于原型的继承。比如,通过将子类的原型指向父类的实例,子类就能继承父类的属性和方法。但要注意constructor属性的修正,避免指向错误。此外,引用中还提到new操作符的原理,创建一个新对象,并将其原型链接到构造函数的prototype,然后执行构造函数绑定this,最后返回对象。 可能用户需要知道原型链的实际应用,比如方法共享、继承实现,以及如何避免常见问题,比如修改原型影响所有实例。此外,引用中提到的instanceof和hasOwnProperty方法也很重要,用于判断类型和属性来源。 用户的问题可能涉及如何实现继承,原型链查找机制,或者为什么方法要放在prototype上。需要结合例子详细解释,比如构造函数、实例、原型之间的关系图,以及原型链的终点是null。还要注意解释__proto__和prototype的区别,前者是实例的属性,后者是构造函数的属性。 可能还需要提到ES6的class语法糖,背后还是基于原型的机制,这样用户理解现代JS写法时不会混淆。同时,注意性能方面的考虑,比如过长原型链会影响查找速度,但通常影响不大。 总结回答结构:先介绍原型和原型链的定义,再讲构造函数、实例、原型对象的关系,接着说明原型链如何实现继承,最后讨论相关方法和应用场景。确保引用正确,比如每个引用对应的知识点,比如原型链的形成[^4],共享方法[^5],继承实现[^3]等。</think>### JavaScript原型与原型链解析 #### 一、原型(Prototype) 1. **基本概念** 每个函数在创建时都会自动关联一个`prototype`属性(显式原型),指向一个原型对象。此对象包含可被所有实例共享的属性和方法。例如: ```javascript function Person() {} Person.prototype.name = "Alice"; const p1 = new Person(); console.log(p1.name); // "Alice" ``` 2. **作用与意义** - **共享方法**:避免重复创建函数,节省内存。例如多个实例共享`sayName`方法。 - **继承基础**:通过原型链实现属性和方法的继承。 --- #### 二、原型链(Prototype Chain) 1. **形成机制** - 每个对象都有一个内部属性`[[Prototype]]`(可通过`__proto__`访问,隐式原型),指向其构造函数的`prototype`。 - 当访问对象属性时,若自身不存在,则沿`__proto__`向上查找,直到`Object.prototype.__proto__`(即`null`),形成链式结构[^2][^4]。 $$ \text{实例} \xrightarrow{\_\_proto\_\_} \text{构造函数.prototype} \xrightarrow{\_\_proto\_\_} \text{Object.prototype} \xrightarrow{\_\_proto\_\_} \text{null} $$ 2. **继承示例** ```javascript function Parent() { this.name = "Parent"; } Parent.prototype.say = function() { console.log(this.name); }; function Child() { Parent.call(this); } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; // 修正构造函数指向 const c = new Child(); c.say(); // "Parent"(通过原型链调用) ``` --- #### 三、关键方法与实践 1. **`new`运算符原理** - 创建空对象,链接到构造函数原型。 - 执行构造函数(绑定`this`),返回对象。伪代码实现: ```javascript function myNew(constructor, ...args) { const obj = Object.create(constructor.prototype); const result = constructor.apply(obj, args); return result instanceof Object ? result : obj; } ``` 2. **类型判断与属性检测** - **`instanceof`**:检查对象是否在原型链上。 - **`hasOwnProperty`**:检测属性是否为对象自身所有(非继承)。 --- #### 四、应用场景与注意事项 1. **应用场景** - **共享工具方法**:将公共方法定义在原型上(如`Array.prototype.map`)。 - **实现继承**:通过修改子类原型指向父类实例。 2. **注意事项** - **原型污染**:修改`Object.prototype`会影响所有对象,需谨慎。 - **性能影响**:过长的原型链会增加属性查找时间。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值