在我初学 JS 语言的继承机制原型和原型链的时候,我一直理解不了这种设计机制,再加上之前原有对 Java继承的理解,在学习 JS 继承机制的设计上踩了一个大坑,很多知识点前期都是死记硬背,无法真正的理解它的设计思想。

思维导图

1.JS 的发展史

要想贯彻 JS 的核心设计思想,我们要从 JS 的诞生说起。

1.1 为什么会诞生 JavaScript ?

相对比较成熟的浏览器是由网景公司发布的,早些年间,浏览器只能浏览网页内容,而不能进行用户交互。比如我们登录输入用户名和密码,在浏览器是不能进行判断用户是否真正输入了,而是通过服务器来判断,如果没有输入,返回错误提示用户,这种设计非常的浪费时间和服务器资源。

为了解决这个问题,网景公司需要开发一种运行在浏览器中的脚本语言,用来简单的做用户输入校验等操作。

当时最流行的语言是面向对象的Java编程语言 ,网景公司为了能够借助 Java将浏览器脚本语言流传开,所以起名 JavaScript。其实两者没有任何的关系。

1.2 存在的问题

JS 中的数据类型设计受当时 Java流行的影响,都是对象类型,这时候就遇到问题了,有对象必然涉及到继承机制,那么 JS 的继承机制要设计成 Java一样呢?还是另有设计思想?

2.JS 继承的设计思想

JS 的开发者想如果设计成像 Java一样有“类”的概念岂不是和 Java一样成为了一种完全面向对象的编程语言了?最后决定自己设计一种继承机制,但是它的设计思想还是采用了 Java的一些特性。

2.1 生成对象

通常 Java 生成对象是通过 new 的方式,通过类生成一个实例对象的过程。但是 JS 中并没有类,那 JS 的设计者要怎么做?

他找到了 Java 和 JS 的共同点就是两者都有构造函数, Java的 new 的过程内部其实调用了构造函数。但是 JS 是没有“类”的概念的,于是 JS 就把new 一个“类”设计成了 new 一个构造函数,于是构造函数成为了一个实例对象的原型对象。

3.为什么要设计原型对象?

上述这样的原型设计有一个致命的缺点就是无法共享公共属性。

因为我们知道,每 new 一个对象,生成的实例是两个不同的对象。所以共有的属性也不是共享的。

所以要设计一个对象专门用来存储对象共享的属性,那么我们叫它「原型对象」。

4.什么是原型对象?

要想让构造函数生成的所有实例对象都能够共享属性,那么我们就给构造函数加一个属性叫做prototype,用来指向原型对象,我们把所有实例对象共享的属性和方法都放在这个构造函数的prototype属性指向的原型对象中,不需要共享的属性和方法放在构造函数中。

这里有一点疑惑就是,我们知道对象可以设置属性,函数也可以设置属性吗?对于初学者来说是比较懵逼的,那我们可以稍微的简单说一下:

JavaScript 中的函数拥有对象的所有能力,也因此可被称作为任意其他类型对象来对待。当我们说函数是第一类对象的时候,就是说函数也能够对象的一些功能,比如添加属性,函数当做参数传递等。

所以说,实例对象一旦通过构造函数创建,就会自动给实例对象赋值上原型对象上共享的属性或方法。说清楚一点就是该对象属性都指向了原型对象的属性值。

5.对象和函数在原型链关系?

上述的图反映了对象以及函数在原型链中的关系,如果你觉的上边的这张图看懵逼了,没关系,我刚开始学习原型链的时候,根本不知道上边这是什么“清明上河图”,小鹿下面通过一步步的拆分讲解,看这张图就非常简单,没错,非常简单。

我们文章的开头也说了什么是原型对象,说白了就是构造函数的一个 prototype属性,这个属性就指向原型对象。

其实我们其中一些连接属性没有讲到,只讲到了prototype属性,下面一张图来将剩下的属性补充完整,我们只要把这张图印到大脑中就可以了。

我们来分析一下上图,首先我们先要声明一个狗的构造函数,定义其名字和体重属性(私有属性),同时每个构造函数我们上边讲到了,都会有一个prototype属性。

这个prototype指向的就是原型对象,原型对象放的就是对象共享的属性。但是注意,原型对象里有一个constructor属性,这个属性又指回了构造函数。

我们通过 new 构造函数生成两个狗的对象实例,一个叫豆豆,一个叫贝贝,这两个是两个不同的对象,名字体重都不相同,但是他们会共享原型对象上的属性 type,它们共有的属性都是犬类。

在 JS 所有对象中,只要是对象,都会有一个内置属性叫做_proto_,而且这个属性是系统自动生成的,只要你创建一个对象,这个对象就有这个属性。这个_proto_属性指向的是原型对象。

通过上边的分布讲解,我们明白了构造函数与对象实例以及原型对象的关系。

总结为一句话为:

构造函数的 prototype 指向原型对象,原型对象有一个 constructor 属性指回构造函数,每个构造函数生成的实例对象都有一个 proto 属性,这个属性指向原型对象。

没错,原型就是这么简单。但是你会发现,原型也是对象呀,你说只要是对象都会有一个_proto_属性指向自身构造函数的原型对象。

没错,要想知道原型对象的_proto_属性指向谁,就要知道是哪个构造函数创建了原型对象?

我们知道,所有的 JS 对象的都是继承了一个叫做 Object 的对象。可以理解为Object 构造函数创造了这个万物,他们的关系如下,和上边是同样的道理,上边总结的那句话好好理解一下。

但是上图中会有一个疑问,Object 构造函数原型对象的也是对象,它肯定也有一个_proto_属性,为什么会指向 null 呢?

我们在拿上述总结的那句话,_proto_属性指向的是自身构造函数的原型对象,自身的构造函数是谁?是 Object 构造函数,那 Object构造函数的原型是谁?当然是本身(如图),所以把_proto_指向了null。

上边的关系如果不仔细整理的话确实很乱,尤其是对于初学者,但是如果像小鹿这样已整理,再乱的关系把它安排的井井有条,没有理解,就多看几篇文章。

6.原型链

我们还有一个问题没有解决就是原型链?既然我么你知道什么是原型了,原型链是什么?顾名思义,肯定是一条链,既然每个对象都有一个_proto_属性指向原型对象,那么原型对象也有_proto_指向原型对象的原型对象,直到指向上图中的null,这才到达原型链的顶端。

不要忘了,上边那种图我们还没有把它理解,我们把图自上而下理解。

第一张图分解,上边小鹿画的图的关系和这个一样的,仔细对比一下,很简单,第一张图就这么解决了。

我们继续向下分割,看第二张图。

第二张图怎么还是那么眼熟呢,这不是小鹿上边分析的 Object 的关系图吗?对的,没错。

第三张图,稍微绕个弯子,但是换汤不换药呀,听小鹿分析来。

看着还是眼熟,只不过把function换成了Function,f 变成了大写的 F,这里涉及到一个知识点就是,在 JS 中,所有的 function函数都是由Function继承来的,可以说是Function是所有 function的祖宗。

那Function是由谁生产来的?我们看到图中的Function函数有_proto_属性了,而且属性指向自己的原型对象,那不就是自己繁衍自己吗?可以这么理解。

小结

这里我们在纵观全图,总结几条定义你比对着图去找。

1、所有的实例的_proto_都指向该构造函数的原型对象(prototype)。

2、所有的函数(包括构造函数)是Function的实例,所以所有函数的 _proto_的都指向Function的原型对象。

3、所有的原型对象(包括 Function的原型对象)都是Object的实例,所以_proto_都指向 Object(构造函数)的原型对象。而 Object构造函数的 _proto_指向 null。

4、Function构造函数本身就是 Function 的实例,所以_proto_指向Function的原型对象。

全篇文章的精华都在最后的总结部分,前边的所有分解讲解是为了让你理解这些函数对象以及原型对象之间的关系,这关系都是固定的,谁指向谁,都是写死额,只要你记住了他们的关系,这张图就理解的差不多了,能够理解完这张图,你的原型和原型链已经了解的很扎实了,但是还需要做一些面试题巩固一下。

图解JS原型和原型链实现原理相关推荐

  1. JavaScript: 原型链继承(原理解析 + 代码实现 + 结构图解)

    文章目录 一 原型搜索机制 1.1 代码实现 1.2 结构图解 1.3 搜索机制 二 原型链代码实现 2.1 代码实现 2.2 结构图解 2.3 链条拓展 三 原型链的缺点 原型链是实现继承的一种方式 ...

  2. JS中的原型和原型链(图解)

    JS中的原型和原型链 讲原型的时候,我们应该先要记住以下几个要点,这几个要点是理解原型的关键: 1.所有的引用类型(数组.函数.对象)可以自由扩展属性(除null以外). 2.所有的引用类型都有一个' ...

  3. 浅谈JS原型与原型链(一)

    最近学习JavaScript原型与原型链的时候,被这块知识烧得脑壳疼,prototype与__proto__混淆不清.网上各种图解,都画的好复杂,绕老绕去,不明所以,看得越来越糊涂.还是亲自动手敲敲, ...

  4. js原型和原型链_重学js --原型与原型链

    一.什么是原型: .每个对象都有一个__proto__属性,并且指向它的prototype原型对象 每个构造函数都有一个prototype原型对象 prototype原型对象里的constructor ...

  5. js原型和原型链_初识JS原型/原型链/原型继承

    本文思路: 原型->原型链->原型继承->基于原型的继承/ES6中的继承->__proto__与prototype 首先我们知道JS中有对象,比如: var 但是在我们没有对这 ...

  6. 图解JavaScript原型和原型链

    先看看最简单的栗子: //构造函数 function People(name, age){ this.name = name;this.age = age; }//原型对象(所有由构造函数实例而来的对 ...

  7. 猿创征文|在工作中彻底搞懂原型和原型链的原理

    前言 在前端开发过程中,涉及到JS原理相关的内容也就是常用的几大模块,不仅常用而且很重要,但是涉及到原理的话会有点难懂,尤其是对JS接触不太久的开发者来讲,甚至工作好几年的开发者也只是在平时开发中知道 ...

  8. 【JS对象】打败JS原型、原型链大恶魔方法详解

    文章目录 什么是对象? 什么是面向对象? 创建对象的方式 原型是什么? __proto__属性 constructor属性 原型链 函数的定义类型有哪些? 函数也是一个对象 完整的原型链 打败恶魔第一 ...

  9. JS原型与原型链详细解释

    文章目录 一.JS原型链简要解释 二.JS原型链详细解释 1.构造函数 2.原型对象 3.`__proto__` 4.原型链 总结 一.JS原型链简要解释 原型是function对象上的一个属性, 它 ...

最新文章

  1. 软件开发行业,年轻与大龄程序员的生存现状
  2. CDIE-2021春季课程内容设计 | 火场逆行
  3. POJ1465 Multiple——Bfs+余数判重——Pku1465
  4. ST17H26的PWM模块
  5. Python执行脚本文件将输出既能显示控制台又能重定向到日志
  6. Struts2 缺少包
  7. poj3264Balanced Lineup(倍增ST表)
  8. linux命令添加文件权限,linux 的常用命令及文件权限管理
  9. JAVA入门级教学之(接口)
  10. 2021年上半年系统集成项目管理工程师案例分析真题及答案解析
  11. 1005. K 次取反后最大化的数组和(javascript)
  12. 获取table控件的某行某列
  13. Mongo, Express, Angular, Node-- MEAN Stack搭建
  14. 【软考系统架构设计师】2013年下系统架构师案例分析历年真题
  15. linux rz sz putty,PuTTY xshell rz sz命令实现上传下载到windows的方法
  16. 计算机专业毕业设计的进度记录,毕业设计周次进度计划及实际进展情况表.doc...
  17. 【OpenStack】OpenStack系列17之OpenStack私有云设计一
  18. Android的界面1080,安卓1080P界面设计规范解读
  19. The CUDA compiler identification is unknown 解决
  20. Windows 下设置自定义域名解析到指定 IP

热门文章

  1. 【高质量github项目合辑】视频、文本的特征提取
  2. 移动渗透测试(dozer,adb,夜神模拟器)
  3. 安装aspera和使用
  4. ventuz 云_Ventuz中的OSC协议(C#)
  5. Wireless Tether 无线共享
  6. 无题----夜雨寄北 李商隐
  7. 夺命雷公狗---无限级分类NO6
  8. 湖南亮仔智能机电有限公司
  9. 超宽带的应用、 开发及发展前景
  10. 扒一扒net.cn这个后缀域名