【JS档案揭秘】第三集 深入最底层探秘原型链
关于这部分我看过大量的文章,数不胜数,包括阮一峰的继承三部曲,还有各种慕课的视频教程,网上无数继承方法的对比。也对很多概念存在长期错误的理解。今天做一个正确的总结,用来给原型链和继承这块知识画上句号,而从深度上来说,则是深入到堆内存中去一探究竟。
业务场景
原型与原型链,从作用上来说,理解它在当前时代用处其实不大,因为ES6的普及,封装的class语法糖让人们很难想再去翻构造函数、原型链这些历史旧账。而且ES6的class除了不支持IE、黑莓这种复古浏览器,主流的现代浏览器都已得到了全面支持。而且再不济,要去兼容IE,也有babel来帮我们转译class语法,用不着去手写prototype,__proto__等关系。
所以研究原型链的作用到底在哪儿呢?我认为它的作用在于从知识层面帮我们看清楚extends和super的本质。至于在业务层面,它并没有任何作用。
原理阐述
首先,prototype属性是函数独有的,它指向一个堆内存中的对象,这个对象就叫原型对象。
原型对象有很多个,每个构造函数都对应着一个原型对象;
当函数作为构造函数使用,也就是实例化时,它会把这个原型对象的指针命名为__proto__,并强加到实例化对象中。这样一来,某个构造函数的prototype属性和通过这个构造函数实例化的所有对象的__proto__属性,都指向某一个原型对象。
所谓原型链,就是将堆内存中不同的原型对象串起来,那怎么让这些分散在不同堆内存的,毫不相关的原型对象串起来呢?
答案就是:引用。因为原型对象也是一个对象,它也有__proto__属性,所以,只要让一个某个原型对象的__proto__属性,指向另外一个原型对象。这样就在毫不相关的两个原型对象之间打通了关系。换言之,这样就实现了继承。
画图理解
在上图中,原型对象1和原型对象2的__proto__属性都默认指向根原型对象。如果要使原型对象1继承原型对象2,则把原型对象1的默认指向根原型对象的__proto__属性,改为指向原型对象2。(灰色箭头转为蓝色虚线箭头)
当然,为了不使这副图变得混乱,我没有把一个东西画出来,那就是原型对象的constructor属性指向其构造函数,也就是说,一个构造函数可以通过prototype属性找到其对应的原型对象,一个原型对象也可以通过自身的constructor属性找到其对应的构造函数,这也侧面印证了:在堆内存中的原型对象是很多的。
ES6的语法糖分析
在ES6中,定义了类,extends和super。它们的本来面目如下:
假设有类A和类B,定义class A extends B。且在类A的constructor构造函数中调用了super函数,实现了类A对类B的继承。
ES6中的类就是构造函数,extends在这里表示A.prototype.__proto__ = B.prototype。而super则是ES5中的A.call(this,args)。args表示A中传入的实例化参数。
关于super,你写不写都可以。如果你要在子类定义一个constructor,且constructor里面要用到this,那么super就是必写的,且需要写在this出现之前;如果不是我刚刚提到的这种情况,那么可以不写;
代码验证
我们敲出一系列代码来验证我的总结:
(验证一:原型链图,通过)
(验证2:ES6语法糖,通过)
【JS档案揭秘】第三集 深入最底层探秘原型链的更多相关文章
- 【JS档案揭秘】第二集 Event loop与执行栈
我时常在思考关于JS的很多知识在工作中有什么用?是否只能存在于面试这种理论性的东西中,对于我们的业务和工作,它们又能扮演怎样的角色.以后在JS档案揭秘的每一期里,都会加入我对于业务的思考,让这些知识不 ...
- 【JS档案揭秘】第一集 内存泄漏与垃圾回收
程序的运行需要内存,对于一些需要持续运行很久的程序,尤其是服务器进程,如果不及时释放掉不再需要的内存,就会导致内存堆中的占用持续走高,最终可能导致程序崩溃. 不再需要使用的内存,却一直占用着空间,得不 ...
- JS function 是函数也是对象, 浅谈原型链
JS function 是函数也是对象, 浅谈原型链 JS 唯一支持的继承方式是通过原型链继承, 理解好原型链非常重要, 我记录下我的理解 1. 前言 new 出来的实例有 _proto_ 属性, 并 ...
- 【JS档案揭秘】第四集 关于this的讨论到此为止
网上关于this的指向问题的博客文章很多,但大多数都是复制粘贴,也不能用简洁的语言讲清楚,而是不停地写一些示例,看得人云里雾里. 这一集,我只给出结论,以及判定的通用方法,至于是否确实如我所讲,大家可 ...
- 关于js的几道经典题(作用域、原型链等)自己做的
1. function test() { var a = 1; setTimeout(function() { alert(a); a = 3; }, 1000); a = 2; setTimeout ...
- JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)
JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...
- 【js基础修炼之路】— 我理解的原型链
提起原型链,大家并不陌生,但是对于新人来说一提到原型方面的东西就会比较懵.在我自一次面试的时候,面试官也给我提了这样的问题,当时就按照我的理解说了一些,但是很肤浅,在此我希望给刚入门的前端小伙伴聊一下 ...
- 三张图理解JavaScript原型链
- JS原型与原型链(好文看三遍)
一. 普通对象与函数对象 JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object ,Function 是JS自带的函数对象. 下面举例说明: function ...
随机推荐
- 西瓜哥:公有云也“All-Flash”?
本文转载自 高端存储知识 Gartner在2018年Market Insight: Preparing for the SSD Rise and HDD Demise一文中指出:当闪存介质降到HDD每 ...
- 转:Java logger组件:slf4j, jcl, jul, log4j, logback, log4j2
先说结论 建议优先使用logback 或 log4j2.log4j2 不建议和 slf4j 配合使用,因为格式转换会浪费性能. 名词:jcl 和 jul 标题中的 jcl 是 apache Jakar ...
- Docker数据挂载
Docker数据管理 在容器中管理数据主要有两种方式: 数据卷(Volumes) 挂载主机目录(Bind mounts) 数据卷 数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很 ...
- 使用 webservice 实现 RPC 调用
WebService 介绍 Web service 是一个平台独立的,低耦合的 web 的应用程序用于开发分布式的互操作的应用程序.Web Service 技术, 能使得运行在不同机器上的不同应用无须 ...
- AutoCAD中的螺旋究竟是什么螺旋?
AutoCad从很早的时候就开始提供了螺旋线的功能,它的用法相对简单,非常适合用来对等距螺旋的理论进行演练. 选择螺旋线工具,首先画出一个基准圆,再向内(或向外)移动鼠标,拖出一个旋转3个周期的螺旋. ...
- Spring boot 集成 阿里 Mqtt
因为公司业务需求,需要接入 阿里Mqtt,自己基于Spring写了一个小demo,记录下来,已备以后需要. 第一步 创建一个实体bean用来装载 MqttClient private MqttClie ...
- Java中通过代码得到int类型数值的二进制形式
一.完整代码 public class BigInteger { int sing; byte[] val; public BigInteger(int val){ // 将传递的初始值,按位取值,存 ...
- C++类成员默认初始值
有时候我们会不给C++类成员变量赋初始值,或是因为忘记在构造函数中指定(C++11可以写在类内),或是觉得没有必要写.然而,因为觉得编译器会把变量赋成0而不写是错误的.本文通过C++标准来解释这个问题 ...
- LiteByte教程
转载请标明原文地址:https://www.cnblogs.com/zhangyukof/p/12073041.html 简介 LiteByte是一种轻量级的二进制数据交换格式.体积小巧.简单易用是设 ...
- Test1016
T1 kom (容斥 \((1s32M)\) 给出\(N\)个互不相同的正整数,统计共有多少对数,它们有公共的一个数字(不一定在同一位置上) 输入 第一行一个正整数 \(N (1 ≤ N ≤ 1 00 ...