JS中的prototype、__proto__与constructor,原型和原型链

理解原型的几个关键点:

1、所有的引用类型(数组、函数、对象)可以自由扩展属性(除null以外);

2、所有的引用类型(对象)都有一个’_ _ proto_ _'属性(也叫隐式原型,它是一个普通的对象),指向原型对象;

3、所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象,该对象就是函数的原型对象,对象中包含所有实例对象可以共享的属性和方法)。’prototype’属性是函数独有的,任何函数在创建的时候,其实会默认同时创建该函数的prototype对象;

4、所有引用类型,它的’_ _ proto_ _'属性指向它的构造函数的’prototype’属性(所以  函数._ _ proto_ _ ===function.prototype);

5、当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。

6、constructor属性也是对象才拥有的,指向该对象的构造函数。函数创建的对象.__proto__ === 该函数.prototype,该函数.prototype.constructor===该函数本身,故通过函数创建的对象即使自己没有constructor属性,它也能通过__proto__找到对应的constructor,所以任何对象最终都可以找到其构造函数(null如果当成对象的话,将null除外)

 

 

原型:

先来看一个原型的例子。

		//这是一个构造函数function Foo(name,age){this.name=name;this.age=age;}/*根据要点3,所有的函数都有一个prototype属性,这个属性是一个对象再根据要点1,所有的对象可以自由扩展属性于是就有了以下写法*/Foo.prototype={// prototype对象里面又有其他的属性showName:function(){console.log("I'm "+this.name);//this是什么要看执行的时候谁调用了这个函数},showAge:function(){console.log("And I'm "+this.age);//this是什么要看执行的时候谁调用了这个函数}}var fn=new Foo('小明',19)/*当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的'prototype'属性中去找*/fn.showName(); //I'm 小明fn.showAge(); //And I'm 19

这就是原型,很好理解。那为什么要使用原型呢?

试想如果我们要通过Foo()来创建很多很多个对象,如果我们是这样子写的话:

	function Foo(name,age){this.name=name;this.age=age;this.showName=function(){console.log("I'm "+this.name);}this.showAge=function(){console.log("And I'm "+this.age);}}

那么我们创建出来的每一个对象,里面都有showName和showAge方法,这样就会占用很多的资源。
而通过原型来实现的话,只需要在构造函数里面给属性赋值,而把方法写在Foo.prototype属性(这个属性是唯一的)里面。这样每个对象都可以使用prototype属性里面的showName、showAge方法,并且节省了不少的资源。
 


 

原型链


理解了原型,那么原型链就更好理解了。

#####下面这段话可以帮助理解原型链
根据要点5,当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的’prototype’属性中去寻找。那又因为’prototype’属性是一个对象,所以它也有一个’_ _ proto_ _'属性。

		// 构造函数function Foo(name,age){this.name=name;this.age=age;}Object.prototype.toString=function(){//this是什么要看执行的时候谁调用了这个函数。console.log("I'm "+this.name+" And I'm "+this.age);}var fn=new Foo('小明',19);fn.toString(); //I'm 小明 And I'm 19console.log(fn.toString===Foo.prototype.__proto__.toString); //trueconsole.log(fn.__proto__ ===Foo.prototype)//trueconsole.log(Foo.prototype.__proto__===Object.prototype)//trueconsole.log(Object.prototype.__proto__===null)//true

 

是不是觉得有点奇怪?我们来分析一下。

 

首先,fn的构造函数是Foo()。所以:
fn._ _ proto _ _=== Foo.prototype
又因为Foo.prototype是一个普通的对象,它的构造函数是Object,所以:
Foo.prototype._ _ proto _ _=== Object.prototype
通过上面的代码,我们知道这个toString()方法是在Object.prototype里面的,当调用这个对象的本身并不存在的方法时,它会一层一层地往上去找,一直到null为止。


所以当fn调用toString()时,JS发现fn中没有这个方法,于是它就去Foo.prototype中去找,发现还是没有这个方法,然后就去Object.prototype中去找,找到了,就调用Object.prototype中的toString()方法。

__proto__属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(父对象)里找,一直找,直到__proto__属性的终点null,再往上找就相当于在null上取值,会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链。
 

另外,在使用原型的时候,一般推荐将需要扩展的方法写在构造函数的prototype属性中,避免写在_ _ proto _ _属性里面。
 

总结:

  • 当所有的实例对象都需要共享属性和方法时,通过原型来实现就是将属性方法放在实例对象的构造函数的prototype属性中(该属性值就是原型对象,包含共享属性和方法);
  •   访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。
  • 根据原型链可以确定继承关系。由于所有的对象的原型链都会找到Object.prototype,因此所有的对象都会有Object.prototype的方法。这就是所谓的“继承”。
  • 对象引用类型通过instanceof来判断。

 

 


版权声明:文章内容主要综合来自链接处,


https://blog.csdn.net/qq_36996271/article/details/82527256

https://blog.csdn.net/cc18868876837/article/details/81211729

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/553958.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win7系统图标异常修复方法

我们在使用win7的时候有可能会碰到图标异常的情况,一般来说都是因为误操作了某些程序或者被某些软件暗改了,这时候我们需要手动去重新设置一下图标,方法也很简单,下面就一起看看win7系统图标异常修复方法吧。 win7系统图标异常修…

彻底理解cookie,session,token

转载自:https://www.cnblogs.com/moyand/p/9047978.html 发展史 1、很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新…

硬盘基本知识(磁头、磁道、扇区、柱面),格式化容量计算

计算差: 在购买硬盘之后,细心的人会发现,在操作系统当中硬盘的容量与官方标称的容量不符,都要少于标称容量,容量越大则这个差异越大。标称40GB的硬盘,在操作系统中显示只有38GB;80GB的硬盘只有7…

在浏览器中输入网址总是打开同一个网站怎么回

我们经常使用浏览器来访问不同的网站,但是有用户发现自己无论在浏览器中输入怎样的网址,打开的同一个网站,这是怎么回事?小编认为应该是用户浏览器被劫持引起的。那么小编下面就给大家讲讲解决的办法。 操作步骤: 1、按WinR键打…

常用校验码(奇偶校验码、海明校验码、CRC校验码)

转载自:https://www.cnblogs.com/VersionP1/p/7779251.html ,作者: FunnyOne 常用校验码(奇偶校验码、海明校验码、CRC校验码) 一、奇偶校验码二、海明校验码三、CRC校验码 计算机系统运行时,各个部之间要进行数据交…

原码、反码、补码、移码

版权声明:本文为CSDN博主「刘水镜」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/liushuijinger/article/details/7429197 原码: 如果机器字长为n&#…

【计算机系统】指令流水线

前言 流水线是指在程序执行时多条指令重叠进行操作的一种准并行处理实现技术。各部件同时处理是针对不同指令而言的,比如说,指令流水线把一条指令分为取指、分析和执行3部分,可以同时处理取指和分析,但是不能同时处理一个部…

win7系统蓝屏代码0x0000003b怎么修复

蓝屏问题是操作系统无法从错误中恢复时,为保护电脑数据文件而强制显示的屏幕图像。并且给用户提供错误代码方便排查,那win7系统蓝屏代码0x0000003b怎么修复呢?就此问题,下面小编介绍win7系统蓝屏代码0x0000003b的修复方法。 win7系统蓝屏代…

计算机系统存储器分类和总线分类

计算机系统存储器分类 1、按存储介质 半导体存储器:用半导体器件组成的存储器。磁表面存储器:用磁性材料做成的存储器。光存储器 2、按存储方式 随机存储器:任何存储单元的内容都能被随机存取,且存取时间和存储单元的物理位置无…

win7看视频卡顿或声音画面不同步的解决步骤

win7看视频卡顿或声音画面不同步怎么办?相信大家在使用电脑观看视频的时候,都有遇到视频卡顿或声画不同步的情况吧,非常影响观看体验。发生这个问题的原因可能是视频本身有问题或者声卡出现问题了。接下来就让小编给大家讲讲win7看视频卡顿或声音画面不…

win7系统怎么打开屏幕键盘

win7系统怎么打开屏幕键盘?我们在电脑没有接入键盘或者键盘失灵等情况下,如果想要输入内容,可以使用系统自带的屏幕键盘。只需要在控制面板中打开屏幕键盘就可以使用了,下面就让我们一起看看win7系统屏幕键盘打开教程吧。 win7系统怎么打开…

Gantt(甘特图)与PERT(项目计划评审技术)图,项目关键路径和松弛时间

甘特图也叫做进度管理图。 他是一种简单的水平条形图,它以日历为基准描述项目任务,水平轴表示日历时间线,每一个线条表示一个任务,任务名称垂直的列在左边列中,图中的线条的起点和终点对应水平轴上的时间,…

win7系统更改密码策略的设置方法

win7的密码策略关系着我们的密码格式、密码需要的字符等,如果我们设置的密码策略太过复杂,可能会让我们在使用密码时非常麻烦,但是也会让我们的密码更难被入侵,那么win7系统如何更改密码策略呢?就此问题,下面一起来看…

软件风险基础知识

在软件开发和实际应用过程中,都会存在一定的风险,而对于该种风险的规避则已经成为软件测试工作开展过程中的核心所在。 软件风险管理的概念: 在软件开发过程中所遭遇到的预算和进度问题以及部分对软件项目会产生影响的因素,都被称…

U盘出现拒绝访问怎么解决

使用U盘启动盘安装系统时需要用到U盘,但是当我们将U盘插上电脑,结果出现拒绝访问的情形,别说是使用U盘启动盘重装系统了,连U盘基础的文件存储功能都无法使用。当U盘出现拒绝访问怎么解决呢?就此问题,下面小编分享u盘拒…

学习阮一峰Javascript模块化编程,requireJS使用

使用背景NOW: 网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式。 项目需要一个团队分工协作、进度管理、单元测试等等......开发者不得不使用软件工程的…

猎豹浏览器禁止跟踪怎么开启 禁止跟踪功能开启方法

为了防止第三方网站跟踪用户活动,包括猎豹浏览器在内的多款浏览器产品都上线了“禁止追踪”功能。不过,需要注意的是,“禁止追踪”功能是需要手动开启的!那么,该怎么操作呢?下面小编就以“猎豹浏览器”为例,分享一下禁…

阮一峰的学习Javascript闭包(Closure)

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 下面就是我的学习笔记,对于Javascript初学者应该是很有用的。 一、变量的作用域 要理解闭包,首先必须理解Javas…

IE浏览器打不开网页有什么解决的方法

IE浏览器打不开网页有什么解决的方法 更新时间:2021-06-06 15:35:38   IE浏览器是Windows电脑自带的浏览器,兼容性强,受到很多用户的喜欢,但是在使用的过程中难免会出现一些问题,比如就有用户发现自己的IE浏览器打不…

阮一峰的JavaScript 的 this 原理

一、问题的由来 学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果。 var obj {foo: function () {} };var foo obj.foo;// 写法一 obj.foo()// 写法二 foo()上面代码中,虽然obj.foo和foo指向同一个函数,…