图解JS原型和原型链实现原理


Posted in Javascript onSeptember 15, 2020

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

JS 中的继承机制思想可以说是学习 JS 的一个核心思想,更可以说是 JS 中的一个命脉,往往这些复杂、抽象的继承关系,以及专业术语、代名词确成为了困扰初学者的绊脚石。当我真正理解它的设计思想时,其实并没有那么复杂,而且觉得非常简单。

在写这篇 JS 的原型和原型链的文章之前,我在谷歌搜索检索了大量的高赞有关 JS 原型和原型链的文章,大部分都是围绕着“是什么”来讲的,导致部分初学者缺少对 JS 继承的设计与实现的前后关联性,还是很难准确的去理解。

我们先要明白,学习这块内容知识要知道设计者“ 为什么这样做 ” 远比 “怎么做的” 重要的多这才是掌握这部分内容的关键。

今天小鹿对 JS 的继承机制要做一个系统的总结,从设计者的角度出发,将复杂的设计思想用动画呈现,将零碎的知识点体系化,争取让你一文搞懂 JS 的继承机制思想(原型和原型链)。

思维导图

图解JS原型和原型链实现原理

1.JS 的发展史

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

1.1 为什么会诞生 JavaScript ?

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

图解JS原型和原型链实现原理

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

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

1.2 存在的问题

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

2.JS 继承的设计思想

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

2.1 生成对象

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

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

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

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

图解JS原型和原型链实现原理

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

4.什么是原型对象?

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

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

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

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

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

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

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

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

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

总结为一句话为:

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

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

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

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

图解JS原型和原型链实现原理

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

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

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

6.原型链

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

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

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

图解JS原型和原型链实现原理

看着还是眼熟,只不过把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的原型对象。

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
用jscript实现新建和保存一个word文档
Jun 15 Javascript
jQuery 插件 将this下的div轮番显示
Apr 09 Javascript
javascript 面向对象编程  function是方法(函数)
Sep 17 Javascript
实现JavaScript中继承的三种方式
Oct 16 Javascript
input输入框的自动匹配(原生代码)
Mar 19 Javascript
用innerhtml提高页面打开速度的方法
Aug 02 Javascript
js window.print实现打印特定控件或内容
Sep 16 Javascript
JS常见疑难点分析之match,charAt,charCodeAt,map,search用法分析
Dec 25 Javascript
如何在vue中使用ts的示例代码
Feb 28 Javascript
Vue2.0实现组件数据的双向绑定问题
Mar 06 Javascript
详解ECMAScript typeof用法
Jul 25 Javascript
JS执行控制之节流模式实例分析
Dec 21 Javascript
vue实现简单全选和反选功能
Sep 15 #Javascript
vscode 调试 node.js的方法步骤
Sep 15 #Javascript
js实现特别简单的钟表效果
Sep 14 #Javascript
仿照Element-ui实现一个简易的$message方法
Sep 14 #Javascript
vue swipeCell滑动单元格(仿微信)的实现示例
Sep 14 #Javascript
JavaScript 如何计算文本的行数的实现
Sep 14 #Javascript
JavaScript实现串行请求的示例代码
Sep 14 #Javascript
You might like
php提示Warning:mysql_fetch_array() expects的解决方法
2014/12/16 PHP
php 解析xml 的四种方法详细介绍
2016/10/26 PHP
php使用str_replace替换多维数组的实现方法分析
2017/06/15 PHP
用于自动添加Digg This!按钮的JavaScript
2006/12/23 Javascript
js中将具有数字属性名的对象转换为数组
2011/03/06 Javascript
在chrome浏览器中,防止input[text]和textarea在聚焦时出现黄色边框的解决方法
2011/05/24 Javascript
JS对象转换为Jquery对象示例
2014/01/26 Javascript
Jquery 实现弹出层插件
2015/01/28 Javascript
基于JSON格式数据的简单jQuery幻灯片插件(jquery-slider)
2016/08/10 Javascript
利用bootstrapValidator验证UEditor
2016/09/14 Javascript
JavaScript每天必学之基础知识
2016/09/17 Javascript
微信js-sdk界面操作接口用法示例
2016/10/12 Javascript
基于jQuery对象和DOM对象和字符串之间的转化实例
2017/08/08 jQuery
javascript获取指定区间范围随机数的方法
2017/09/08 Javascript
原生JS实现ajax与ajax的跨域请求实例
2017/12/01 Javascript
vue element-ui 绑定@keyup事件无效的解决方法
2018/03/09 Javascript
Vue前后端不同端口的实现方法
2018/09/19 Javascript
layui弹出框Tab选项卡的示例代码
2019/09/04 Javascript
关于vue 结合原生js 解决echarts resize问题
2020/07/26 Javascript
python中的字典详细介绍
2014/09/18 Python
Python中的choice()方法使用详解
2015/05/15 Python
浅析Python中元祖、列表和字典的区别
2016/08/17 Python
多个python文件调用logging模块报错误
2020/02/12 Python
什么是python的必选参数
2020/06/21 Python
Django框架实现在线考试系统的示例代码
2020/11/30 Python
matplotlib自定义鼠标光标坐标格式的实现
2021/01/08 Python
涂鸦板简单实现 Html5编写属于自己的画画板
2016/07/05 HTML / CSS
台湾屈臣氏网路商店:Watsons台湾
2020/12/29 全球购物
银行毕业实习自我鉴定
2013/09/19 职场文书
大学毕业后的十年规划
2014/01/07 职场文书
总会计师岗位职责
2014/02/19 职场文书
协商一致解除劳动合同协议书
2014/09/14 职场文书
关于空气污染危害的感想
2015/08/11 职场文书
诚信教育主题班会
2015/08/13 职场文书
初三化学教学反思
2016/02/22 职场文书
CSS3 菱形拼图实现只旋转div 背景图片不旋转功能
2021/03/30 HTML / CSS