首页 > 编程语言 >详解JavaScript中的__proto__和prototype

详解JavaScript中的__proto__和prototype

时间:2023-06-05 18:34:43浏览次数:64  
标签:__ proto 对象 JavaScript JS 原型 prototype

目录

  对于 JS 来说,__proto__prototype 的区别是个绕不开的话题。本文就试图从它们的根本上说清楚它们是什么,又有什么区别,所以本文会从 JS 的对象开始说起,以其期待把本文的主题说透彻说明白。

一、JS的对象创建方法

 大家都知道,在JS 的世界中有一句话:万物皆对象。而 JS 中的对象跟其他强类型的语言中的对象又有天壤之别,本文无意讨论 JS 中对象跟譬如 C#、java 等强类型语言中的对象的区别,不过还是要说下 JS 中对象创建的方法。

  JS 语言本身非常灵活(不严谨),它的对象也非常灵活,比如 JS 允许动态的给对象添加属性(此处的动态添加属性指的是添加之前没有定义过的属性)。JS 创建对象的方式也是很多的,比如要创建一个用来描述“人”的对象p,该对象具有 name 、age 属性和say()方法。那么创建对象的手段至少有如下几种:

  • 使用Object创建
var p = new Object();
p.name = "homes";
p.age = 32;
p.say = function(){
    console.log("hello");
}
  • 使用字面量方式
var p = {
    name: "homes",
    age: 32,
    say: function () {
        console.log("hello");
    }
};
  • 使用构造函数
var Person = function () {
    this.name = "homes";
    this.age = 32;
    this.say = function () {
        console.log("hello");
    }
}
var p = new Person();

  等等等,总之还有很多方法,比如使用原型来创建对象,使用拷贝方式,使用工厂方式。其实这些方式只是形式上有所变化而已。

这里重点要讨论的是第3种,使用构造函数创建对象

二、双对象法则

  首先观察使用构造函数创建对象的代码,var Person = function( ){....} ,由于 JS 没有“类”的概念,其实这里的 Person 其实就是个函数;不过在 JS 的世界里还有一句话:万物皆对象,所以函数也是个对象(是由JS内置对象Function实例化出来的),那么以此得出 Person 是一个函数性质的对象。

  上面这句话要说明什么呢?

  重点来了,在 JS 中如果一个对象是函数,那么这个对象是由两部分构成的,一个是这个函数的定义部分,如果这个函数被当做构造函数来用了,那么这第一部分就是这个构造函数。

  第二部分,是这个函数的原型对象。

  很多人在看到“原型对象”这个词的时候彻底懵逼,在这里必须把这个"原型"这个词说明白了。我第一次看到这个词“原型对象”的时候,我就想起了西游记,里边的妖怪最后都要现原形,难不成 JS 的世界就是妖怪的世界?每个对象都有个“原形”?可以通过某种手段让一个 JS 对象现原形?这是大错特错的。

  这里的“原型对象”只不过是起个名字而已,我们就这样理解就好了,每一个函数都是对象,当代码运行时,在内存中每个对象都由2块内容来合成这1个对象;换句话说代码运行时,内存里有2个独立的空间,这两个独立空间存储2个不同的对象,1个是函数体本身,一个是另外一个对象,这2个东西合成我们定义的一个函数对象,而这个“另一个对象”我们起名叫做“原型对象”,仅此而已。

那接下来问题来了

  1、那个“原型对象”有什么用?

  2、既然一个函数对象是由2部分组成的,那这两部分又是如何联系起来的? 

三、__proto__prototype

prototype是什么?

  先不管那个额外的“原型对象”有什么鸟用,我们先看看一个函数对象的两部分是如何联系起来的。为什么要回答这个问题,因为如果两部分不能有效的联系起来,当我们 JS 程序中有多个函数对象时岂不是要乱套?

  它们两部分之间是通过prototype联系起来的(prototype指向的对象就是我们说的原型对象)。看图

img

  如图,我们上边声明了Person构造函数,当程序运行时,内存里会有2个部分,一个是左边的方框,代表该函数体,右边的方框代表该函数的另一部分,即它的“原型对象”。function的内存中,除了有我们声明name,age属性,还有一个prototype,这个属性是一个指针,它指向自己的原型对象所在地址。同理,每个原型对象也有一个属性,叫constructor,也是个指针,它指回了自己的另一半,即该原型所从属的构造函数。

  比如,我们可以使用如下语句:Person.prototype,来访问函数自己的原型对象。

  需要注意的是,如果这个对象不是函数,那么该对象不具有prototype属性。例如:

var a = {
    name: "homes",
    age: 32,
    say: function () {
        console.log("hello");
    }
};
console.log(a.prototype);				// 输出:undefined

var b = new Date();
console.log(b.prototype);				// 输出:undefined
var c = new String("123");
console.log(c.prototype);				// 输出:undefined

  即使一个对象是根据构造函数实例化出来的,由于该对象不是函数,它也不具有prototype属性。例如:  

var Person = function () {
    this.name = "homes";
    this.age = 32;
    this.say = function () {
        console.log("hello");
    }
}
var p = new Person();
console.log(p.prototype);				// 输出:undefined

  说白了,prototype属性是只能通过 函数名.prototype 的形式来访问。

__proto__又是什么?

  首先要注意,这个“__proto__”左右两边是2个连续的下划线。

  它是 JS 中所有对象都有的属性,既然如此,函数也是个对象,那么它也必须有,所以上图可以再改改,把这个__proto__加上去。

img

   如上图所示,不管是函数本身那个框框,还是它的原型对象那个框框,都有__proto__属性,并且__proto__属性也是一个指针,它指向“它的构造函数的原型对象”。怎么理解这句话?

  在 JS 的世界里,每一个函数都是 Function 对象的实例,也就是通过 new Function() 构造出来的。所以在这里,Person 函数也是由 Function 构造出来的一个实例,函数实例。所以,Person函数的__proto__指向了Function函数的原型对象,也就是Function.prototype

  而 Person 的原型对象 Person.prototype 也是个对象,它也有__proto__属性,它的__proto__也要指向“它的构造函数的原型对象”,那么这个 Person 的原型对象的构造函数的原型对象又是谁呢?答案是Object的原型对象,也就是Object.prototype

  接下来深入一步,既然Function的原型对象 Function.prototype是个对象,它也有__proto__属性吧,那Function.prototype.__proto__又指向谁呢?答案是指向 Object的原型对象,也就是Object.prototype

  接下来再深入一步,Object.prototype__proto__又指向谁呢?由于Object对象就是 JS 的世界中的原始天尊了,所以Object.prototype.__proto__指向null

  好绕啊,我决定画个图。

img

  请仔细观察此图,这个图里有一个非常诡异的浅蓝色箭头,它描述的信息是Object__proto__指针指向了Function.prototype。这是几个意思?你刚刚不是说了Object就相当于JavaScript的原始天尊了吗?额,额,好吧,Function对象是原始天尊的爸爸级别的。换句话说Object也是Function搞出来的。。。。

那根据构造函数Person( ) 创建出来的实例呢?

  例如 : var p = new Person( );

  由Person()函数构造出来的实例p就只是个普通对象了,所以p不是函数,也就是说,p这个对象只有__proto__属性,没有prototype属性。p.__proto__指向“它的构造函数的原型对象”,所以p.__proto__指向的对象是Person.prototype,因为p的构造函数是Person,它的原型对象就是Person.prototype。如图。

img

  • 如图,虚线表示实例化的意思,p是由Person()构造函数实例化出来的。由于p不是函数,所以p没有它自己的"原型对象"。

总结:

  每个对象都有__proto__属性,它指向该对象的构造函数的原型对象。

  函数是一种特殊的对象,它由2部分构成,一部分是函数体本身,一部分是它的原型对象

  函数除了有属性__proto__,还有属性prototypeprototype指向该函数的原型对象。

  到这里我们把__proto__prototype基本说明白了,那么最后又引申出一个问题:这个该死的原型对象有什么用?

参考文章:

https://www.cnblogs.com/ldq678/p/9381327.html

https://blog.csdn.net/m0_49016709/article/details/123254326

标签:__,proto,对象,JavaScript,JS,原型,prototype
From: https://www.cnblogs.com/hhddd-1024/p/17458678.html

相关文章

  • 释放资源的方案一:try-catch-finally
          ......
  • LuoguP4318 完全平方数
    标签:莫比乌斯函数,容斥完全平方数题目描述小X自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。这天是小X的生日,小W想送一个数给他作为生日礼物。当然他......
  • 前端遗忘知识点
    #JS1.基本数据类型numberstringbooleanundefindnullbigintsymbol2.交互alertconfirm确认prompt带输入的确认3.Object.assign(a,b,c)进行合并将a,b,c中的同名属性进行合并4.计算属性名可以将变量的计算结果作为属性的名称```letname="firstname"letperson={......
  • 苹果MacOS系统傻瓜式本地部署AI绘画Stable Diffusion教程
    StableDiffusion的部署对小白来说非常麻烦,特别是又不懂技术的人。今天分享两个一键傻瓜式安装包,对小白来说非常有用。下面两个任选一个安装就可以。一、DiffusionBee简单介绍DiffusionBee是基于stablediffusion的一个安装包,有图形界面,直接安装就能使用,安装完成后会自行下载两......
  • 算法——字符串(一)
    1、两数相加1classSolution{2publicListNodeaddTwoNumbers(ListNodel1,ListNodel2){3ListNodepre=newListNode();4ListNodecur=pre;5intcarry=0;6while(l1!=null||l2!=null||carry!=0){7......
  • 广州app软件定制开发公司哪家好?
    广州不仅是一座文化名城,是岭南文化的中心城市和南越古国的国都,还是国内四大一线城市,经济发展名列前茅。在广州,app软件定制开发还是很盛行的,那如果想在广州做app软件定制开发,找哪家app软件定制开发公司好呢?在广州,app软件定制开发公司数量繁多,不过质量参差不齐,如果稍有不慎,很容易碰......
  • 直线导轨在输送线中的应用
    输送线主要是完成其物料的输送任务,广泛运用在环绕库房、生产车间和包装车间的场地,它的工作原理是工装板承载着物料在线上运动,摩擦运动驱动力来源于摩擦轮转动带动光板往前走,而摩擦轮动力则由齿轮进行联动传输。顶升部位配备直线导轨,我们可以根据型号不同选择载荷,安装导轨的时候,通常......
  • 初遇C++(一)
    认识C++C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机,20世纪80年代,计算机界提出了OOP(objectorientedprogramming:面向对象)思想,支持面向对象的程序设计语言应运而生。1982年,本贾......
  • 13、基于 VRRP Script 实现其它应用的高可用性(Haproxy和Nginx)
    基于VRRPScript实现其它应用的高可用性keepalived利用VRRPScript技术,可以调用外部的辅助脚本进行资源监控,并根据监控的结果实现优先动态调整,从而实现其它应用的高可用性功能VRRPScript配置分两步实现定义脚本:vrrp_script:自定义资源监控脚本,vrrp实例根据脚本返回值,公共......
  • 【React工作记录八十七】React+antDesign实现上传图片功能(类组件)
    前言大家好我是歌谣今天继续给大家带来工作中实战部分的一些代码的封装和认识需求实现1可以支持上传最多九张图片2图片支持预览替换删除3支持自定义上传文件大小格式未上传提示实现效果子组件封装UploadImage组件*@Description:公共上传图片*@param{Array}type图片......