写给小白的js高级原型链

吕旷
• 阅读 1147

前言

广告: 最近github上新开了一个仓库[May-Nodes](https://github.com/maycope/Ma...,包括但不限于之前面试遇到的相关数据库,计算机操作系统,Java基础知识,计算机网络以及LeetCode等算法题解等知识。届时也会整理学习使用的PDF文档与资源。有需要的小伙伴  可以点个关注和`star`。在持续更新中,总会遇到你想要的。

本篇文章是最近应公司要求学习ES6的记录性博客,博客原型来源于B站视频源地址,主要学习和记录的是原型链部分内容,感觉老师讲的很好,所以想着以自己的理解进行一个深入的记录处理,也希望能够尽量详细的讲解清楚其中的内容,帮助大家理解这部分的知识,个人感觉这部分的内容还是蛮套娃的,所以想要完完全全明白,建议看源视频,本篇博客作为收藏,忘记时候观看。

正文

前景提要

首先在讲解本部分内容之前,先设想一个场景,有以下代码:

我们在进行打印的时候,打印出来了false,因为我们在进行构造函数实例化的时候,是会创建出来两个对象,同时对于这两个对象存放在内存中的位置也不一样,这点类似于java的面试题目== 和 equals的区别:其实对于 Object类的equals方法来说,看过源码的都知道,底层使用到的还是 == 来判断是否相等,但是不幸的是,很多继承Object的类都会对基础的方法进行重新,最后导致的结果在很多的时候,== 判断的是地址值是否是相同的,但是equals来说,判断的是值是否相同。

   function Person (name,age){
            this.name=name;
            this.age=age;
            this.doSomething = function(){
                console.log("I can do something")
            }
        }
        var man = new Person('Tom',22);
        var woman = new Person('Amy',21);
        console.log(man.doSomething === woman.doSomething);
        // 打印false

所以在上面的代码中,我们有一个方法,然后被实例化两次,被分配了两个不同的内存空间,这个时候使用到 == 来判断时候就会导致不一样的情况,但是我们想一下,对于一个方法,在实例化一次就需要分配给他一定的空间,这样下去空间的利用率就会很低,所以我们希望的是所有的对象使用到同一个函数,这样也会比较节约内存。

构造函数原型 prototype(原型)

对于构造函数来说,通过原型分配的函数是所有对象所共享的

什么是prototype:对于js来说,规定了每一个构造函数都有一个prototype属性,指向了另外一个对象。

但是注意的是,这个prototype其实也是一个对象,同时这个对象所具有的所有属性和方法都会被构造函数所拥有。对于prototype来说翻译过来就是原型,同时是一个对象,所以理解为对于任意的构造函数,都有其自己的原型对象

有什么用:这里我们知道了对于每一个构造函数都会有其的原型对象,所以就可以将那些不变的方法,直接定义在prototype对象上,这个时候,所有的实例对象也都可以共享这些属性和方法:

写给小白的js高级原型链

下面我们就可以进行进行代码的修改:

   function Person (name,age){
            this.name=name;
            this.age=age;   
        }
        Person.prototype.doSomething = function(){
                console.log("I can do something")
            }
        var man = new Person('Tom',22);
        var woman = new Person('Amy',21);
        console.log(man.doSomething=== woman.doSomething);
        // 打印true

什么是原型:

就是一个对象,但是是每一个构造函数都会拥有的对象,我们也称为原型对象。

原型的主要作用

对于方法的共享,我们可以将方法定义在原型上面,所有的实例都能够使用到这个方法,并且不需要再开辟新的空间。

对象原型

这里,我们是把方法定义在了构造函数的原型对象上面,为什么实例化之后,我们的man这个对象就能够使用呢?

是因为在我们的对象的身上也有一个对象原型,叫做 _proto _前后都有两个下划线_对于 这个东西来说是一个属性,但是有指向的值:指向了构造函数的prototype原型对象,之所以说我们能够使用到构造函数上的方法,就是因为有对象proto原型的存在。我们来打印以下我们的man对象看看是什么情况:

写给小白的js高级原型链

可以看到对于我们的man对象来说有一个proto属性,里面存放的是一个对象。所以说虽然我们的man对象没有确切的方法,但是我有一个属性,我的属性指向了一个prototypeprototype(原型对象)里面有具体的方法。就等于说两者之间是等价的。

我们进行一个打印处理:发现结果显示true,证明是完完全全等价的。

方法的查找规则:当我们使用到man对doSomething方法进行调用的时候,若是发现有这个方法,就直接进行调用即可,若是没有这个方法,因为我们有proto(这里省略四个下划线),所以若是对于构造函数的原型对象上有这个方法,还是可以进行完美的调用:

注意:对于 proto来说 存在的意义在于 为对象的查找提供给一个方向,或者说是一条路线,但是是一个非标准属性,在开发中,不可以使用这个属性,它也只是指向原型对象prototype

写给小白的js高级原型链

下面来看一下,构造函数,构造函数的原型对象,对象实例之间的关系:

写给小白的js高级原型链

构造函数,实例,原型对象三者之间关系

无论是对于我们的原型对象,或者是说,实例的proto都有一个构造函数见下图:

写给小白的js高级原型链

那问题来了对于他们之间到底是什么关系呢?

如下图所示,就是说,构造函数有一个prototype对象,其有一个属性叫做constructor又指向了Person本身。同时对于实例化的对象的proto属性也有一个属性叫做constructor,也可以指向Person本身,但是是通过prototype指向。

写给小白的js高级原型链

原型链

Person.prototype.__proto__

我们知道的是对于 Person的prototype叫做原型对象但是只要是对象就还是会有对象的原型的概念,那它到底有没有呢,我们来进行一个测试:

写给小白的js高级原型链

因为我们的proto和prototype是一一对应的,现在我们进行打印验证:

写给小白的js高级原型链于是我们就可以得到如下的结论:对于 构造函数的原型对象里面的原型指向的是Object里面的原型对象。可能优点绕口,明白原型对象是prototype,对象原型是proto

写给小白的js高级原型链

Object.prototype.__proto__

现在思考的是对于 Object原型对象肯定也是Object 构造函数创建出来的。 如下图:

写给小白的js高级原型链

但是Object的原型对象也是一个对象,那他的proto是什么呢,我们进行一个打印。

发现是一个null值。

写给小白的js高级原型链

于是最后的原型链为:

写给小白的js高级原型链

于是我们就有了:

对于一个普通的实例对象来说拥有属性proto,指向了构造函数的prototype(原型对象),

构造函数的原型对象也是一个对象,也有属性proto,指向的是Object构造函数的prototype(原型对象),

Object构造函数的原型对象也是一个对象,也有属性proto,指向的是null。

所以以上的一条条的链就是我们所说的原型链。

所以以后在访问成员或者时候就可以按照就近原则一层层的进行数据的访问,一层层的向上查找

后记

对于原型链大体来说就是以上的一些细节部分,访问数据的时候,还是采用就近的原则,这一点也是毋庸置疑的,在他们之间链式相关链的过程中,主要是搞清楚对于prototype是一个对象,而对象就会有proto属性的思路,就可以轻松完成对原型链的理解。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
11个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
PPDB:今晚老齐直播
【今晚老齐直播】今晚(本周三晚)20:0021:00小白开始“用”飞桨(https://www.oschina.net/action/visit/ad?id1185)由PPDE(飞桨(https://www.oschina.net/action/visit/ad?id1185)开发者专家计划)成员老齐,为深度学习小白指点迷津。
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
4个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(