理解JS的6种继承方式

【转】重新理解JS的6种继承方式

写在前面

一直不喜欢JS的OOP,在学习阶段好像也用不到,总觉得JS的OOP不伦不类的,可能是因为先接触了Java,所以对JS的OO部分有些抵触。

偏见归偏见,既然面试官问到了JS的OOP,那么说明这东西肯定是有用的,应该抛开偏见,认真地了解一下

约定

P.S.下面将展开一个有点长的故事,所以有必要提前约定共同语言:

/** 约定*/
function Fun(){// 私有属性var val = 1;        // 私有基本属性var arr = [1];      // 私有引用属性function fun(){}    // 私有函数(引用属性)// 实例属性this.val = 1;               // 实例基本属性this.arr = [1];             // 实例引用属性this.fun = function(){};    // 实例函数(引用属性)
}// 原型属性
Fun.prototype.val = 1;              // 原型基本属性
Fun.prototype.arr = [1];            // 原型引用属性
Fun.prototype.fun = function(){};   // 原型函数(引用属性)

上面的约定应该是比较合理的,如果难以理解,可以查看黯羽轻扬:JS学习笔记2_面向对象,了解更多的基本常识

一.简单原型链

这是实现继承最简单的方式了,真的超简单,核心就一句话(在代码中用注释标明了)

1.具体实现

function Super(){this.val = 1;this.arr = [1];
}
function Sub(){// ...
}
Sub.prototype = new Super();    // 核心var sub1 = new Sub();
var sub2 = new Sub();
sub1.val = 2;
sub1.arr.push(2);
alert(sub1.val);    // 2
alert(sub2.val);    // 1alert(sub1.arr);    // 1, 2
alert(sub2.arr);    // 1, 2

2.核心

拿父类实例来充当子类原型对象

3.优缺点

优点:

  1. 简单,易于实现

缺点:

  1. 修改sub1.arr后sub2.arr也变了,因为来自原型对象的引用属性是所有实例共享的。

    可以这样理解:执行sub1.arr.push(2);先对sub1进行属性查找,找遍了实例属性(在本例中没有实例属性),没找到,就开始顺着原型链向上找,拿到了sub1的原型对象,一搜身,发现有arr属性。于是给arr末尾插入了2,所以sub2.arr也变了

  2. 创建子类实例时,无法向父类构造函数传参

二.借用构造函数

简单原型链真够简单,可是存在2个致命缺点简直不能用,于是上个世纪末的jsers就想办法fix这2个缺陷,然后出现了借用构造函数方式

1.具体实现

function Super(val){this.val = val;this.arr = [1];this.fun = function(){// ...}
}
function Sub(val){Super.call(this, val);   // 核心// ...
}var sub1 = new Sub(1);
var sub2 = new Sub(2);
sub1.arr.push(2);
alert(sub1.val);    // 1
alert(sub2.val);    // 2alert(sub1.arr);    // 1, 2
alert(sub2.arr);    // 1alert(sub1.fun === sub2.fun);   // false

2.核心

借父类的构造函数来增强子类实例,等于是把父类的实例属性复制了一份给子类实例装上了(完全没有用到原型)

3.优缺点

优点:

  1. 解决了子类实例共享父类引用属性的问题

  2. 创建子类实例时,可以向父类构造函数传参

P.S.前辈就这么高效,两个缺陷瞬间修复

缺点:

  1. 无法实现函数复用,每个子类实例都持有一个新的fun函数,太多了就会影响性能,内存爆炸。。

P.S.好吧,刚修复了共享引用属性的问题,又出现了这个新问题。。

三.组合继承(最常用)

目前我们的借用构造函数方式还是有问题(无法实现函数复用),没关系,接着修复,jsers吭哧吭哧又搞出了组合继承

1.具体实现

function Super(){// 只在此处声明基本属性和引用属性this.val = 1;this.arr = [1];
}
//  在此处声明函数
Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};
//Super.prototype.fun3...
function Sub(){Super.call(this);   // 核心// ...
}
Sub.prototype = new Super();    // 核心var sub1 = new Sub(1);
var sub2 = new Sub(2);
alert(sub1.fun === sub2.fun);   // true

2.核心

把实例函数都放在原型对象上,以实现函数复用。同时还要保留借用构造函数方式的优点,通过Super.call(this);继承父类的基本属性和引用属性并保留能传参的优点;通过Sub.prototype = new Super();继承父类函数,实现函数复用

3.优缺点

优点:

  1. 不存在引用属性共享问题
  2. 可传参
  3. 函数可复用

缺点:

  1. (一点小瑕疵)子类原型上有一份多余的父类实例属性,因为父类构造函数被调用了两次,生成了两份,而子类实例上的那一份屏蔽了子类原型上的。。。又是内存浪费,比刚才情况好点,不过确实是瑕疵

P.S.如果无法理解这个”多余“,可以查看黯羽轻扬:JS学习笔记2_面向对象,文章末尾有更详细的解释

四.寄生组合继承(最佳方式)

从名字就能看出又是对组合继承的优化,不是说组合继承有瑕疵吗,没关系,我们接着追求完美

1.具体实现

function beget(obj){   // 生孩子函数 beget:龙beget龙,凤beget凤。var F = function(){};F.prototype = obj;return new F();
}
function Super(){// 只在此处声明基本属性和引用属性this.val = 1;this.arr = [1];
}
//  在此处声明函数
Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};
//Super.prototype.fun3...
function Sub(){Super.call(this);   // 核心// ...
}
var proto = beget(Super.prototype); // 核心
proto.constructor = Sub;            // 核心
Sub.prototype = proto;              // 核心var sub = new Sub();
alert(sub.val);
alert(sub.arr);

P.S.等等,生孩子函数是啥东西,怎么没听过?还有标明了核心的3句话,怎么没看明白?别着急,我们喝杯茶接着看

2.核心

用beget(Super.prototype);切掉了原型对象上多余的那份父类实例属性

P.S.啥?没看明白?哦哦~,忘记说原型式和寄生式继承了,就说怎么总觉得忘了锁门。。这记性

P.S.寄生组合式继承,这名字不是很贴切,和寄生式继承关系并不是特别大

3.优缺点

优点:完美了

缺点:理论上没有了(如果用起来麻烦不算缺点的话。。)

P.S.用起来麻烦是一方面,另一方面是因为寄生组合式继承出现的比较晚,是21世纪初的东西,大家等不起这么久,所以组合继承是最常用的,而这个理论上完美的方案却只是课本上的最佳方式了

五.原型式

其实介绍完上面的完美方案就可以结束了,但从组合继承到完美方案好像有一段不小的思维跳跃,有必要把故事说清楚

1.具体实现

function beget(obj){   // 生孩子函数 beget:龙beget龙,凤beget凤。var F = function(){};F.prototype = obj;return new F();
}
function Super(){this.val = 1;this.arr = [1];
}// 拿到父类对象
var sup = new Super();
// 生孩子
var sub = beget(sup);   // 核心
// 增强
sub.attr1 = 1;
sub.attr2 = 2;
//sub.attr3...alert(sub.val);     // 1
alert(sub.arr);     // 1
alert(sub.attr1);   // 1

P.S.诶~看到了没,生孩子函数beget出现了

2.核心

用生孩子函数得到得到一个“纯洁”的新对象(“纯洁”是因为没有实例属性),再逐步增强之(填充实例属性)

P.S.ES5提供了Object.create()函数,内部就是原型式继承,IE9+支持

3.优缺点

优点:

  1. 从已有对象衍生新对象,不需要创建自定义类型(更像是对象复制,而不是继承。。)

缺点:

  1. 原型引用属性会被所有实例共享,因为是用整个父类对象来充当了子类原型对象,所以这个缺陷无可避免

  2. 无法实现代码复用(新对象是现取的,属性是现添的,都没用函数封装,怎么复用)

P.S.这东西和继承有很大关系吗?为什么尼古拉斯把它也列为实现继承的一种方式?关系不大,但有一定关系

六.寄生式

这名字太扯了,而且寄生式是一种模式(套路),并不是只能用来实现继承

1.具体实现

function beget(obj){   // 生孩子函数 beget:龙beget龙,凤beget凤。var F = function(){};F.prototype = obj;return new F();
}
function Super(){this.val = 1;this.arr = [1];
}
function getSubObject(obj){// 创建新对象var clone = beget(obj); // 核心// 增强clone.attr1 = 1;clone.attr2 = 2;//clone.attr3...return clone;
}var sub = getSubObject(new Super());
alert(sub.val);     // 1
alert(sub.arr);     // 1
alert(sub.attr1);   // 1

2.核心

给原型式继承穿了个马甲而已,看起来更像继承了(上面介绍的原型式继承更像是对象复制)

注意:beget函数并不是必须的,换言之,创建新对象 -> 增强 -> 返回该对象,这样的过程叫寄生式继承,新对象是如何创建的并不重要(用beget生的,new出来的,字面量现做的。。都可以)

3.优缺点

优点:

  1. 还是不需要创建自定义类型

缺点:

  1. 无法实现函数复用(没用到原型,当然不行)

P.S.剧情解析:有缺陷的寄生式继承 + 不完美的组合继承 = 完美的寄生组合式继承,不妨回去找找看哪里用到了寄生

七.6种继承方式的联系

继承

P.S.虚线表示辅助作用,实线表示决定性作用

参考资料

  • 《JavaScript高级程序设计》

  • 《JavaScript语言精粹》

转载于:https://www.cnblogs.com/liyuspace/p/7757685.html

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

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

相关文章

android 滚动列表框,建立滚动列表框

另一个可代替一组单选按钮及复选框的是滚动列表框(见图6.9)。使用滚动列表框,你可以建立一个选项列表,用户可以从中选择一个或多个选项。你可以使用建立下拉式列表框的标识符来建立一个滚动列表框,只是使用不同的属性。下面是个例子&#xff…

collection集合 多少钱_面试必备-Java集合框架

Java集合框架面试题常见集合集合可以看作是一种容器,用来存储对象信息。 数组和集合的区别: (1)数组长度不可变化而且无法保存具有映射关系的数据;集合类用于保存数量不确定的数据,以及保存具有映射关系的数…

html鼠标滚动图片折叠,鼠标滑过图片3D折叠效果

本教程我们将使用CSS3 3D transforms和jQuery来制作一个神奇的3D折叠效果。在我们的demo中,图片在鼠标滑过的时候被折叠,空出来的部分将显示图片的一些信息。我们将创建一个放置图片html结构,当鼠标滑过它时,使用jQuery来将折叠或…

微信小程序开发之普通链接二维码

本文主要介绍扫普通链接二维码打开小程序, 详情请看官方文档https://mp.weixin.qq.com/debug/wxadoc/introduction/qrcode.html 配置普通链接二维码规则 生成二维码 访问https://cli.im/url,将https://test.com/linkcode?id1_2生成二维码图片 小程序接收…

html checked属性值,HTML复选框的checked属性的值是多少?

8种机械键盘轴体对比本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?我们都知道如何在HTML中构成复选框输入:我不知道 - 选中复选框的技术上正确的值是多少?我已经看到了这些工作:答案是无关紧要的…

3位水仙花数计算pythonoj_Python解答蓝桥杯省赛真题之从入门到真题

若发现此文章消失,则是在等待审核中,稍等一会儿即可显示,谢谢。 另外,我会尽量晚上上传更新题目。 此文章太长了,导致MD编辑器很卡,另写了一篇接续 传送门 Python解答蓝桥杯省赛真题之从入门到真题 &#x…

uniapp怎么解析html字符串,uniapp富文本解析插件的详细使用教程

如果你作为文章资源类或者博客类的小程序你就会发现,很多时候你的文章数据都是html格式或md格式,这样如果不经过处理,会非常难看,所以富文本解析就显得格外重要了,今天给大家写一个uniapp怎么使用富文本解析插件的教程…

c++和python有联系吗_Python和C++交互

关键字:Python 2.7,VS 2010,swig OS:Win8.1 with update。 1.下载swig:http://www.swig.org/download.html 2.将swig的路径添加到环境变量Path,例如set pathC:\swigwin-3.0.2。 3.用VS创建一个win32 consol…

html播放切片,[Html/Css]网页切片

简介这篇文章主要介绍了[Html/Css]网页切片以及相关的经验技巧,文章约2269字,浏览量461,点赞数4,值得参考!网页切片 前端必须掌握的技能,切片,虽然说难也不难,简单也确实是挺简单的&…

设计模式学习总结(一)——设计原则与UML统一建模语言

目录 一、概要1.1、设计模式定义1.2、设计模式分类1.3、设计模式书籍二、UML统一建模语言2.1、UML分类2.2、类图2.2.1、关联2.2.2、聚合/组合2.2.3、依赖2.2.4、泛化(继承)三、设计原则2.1、单一职责原则(SRP)2.2、开闭原则&#…

计算机与生命科学专业排名,2019软科世界一流学科排名发布,54个专业TOP10牛校榜单全给你...

原标题:2019软科世界一流学科排名发布,54个专业TOP10牛校榜单全给你软科26日正式发布2019“软科世界一流学科排名”(Shanghai Rankings Global Ranking of Academic Subjects)。2019年排名覆盖54个学科,涉及理学、工学、生命科学、医学和社会…

python入门心得_一天入门 Python 的一些心得

1. 前言 好久没写文了。最近在搞一些好玩的技术用到了 Python 。我原以为要花些时日,谁知道第一天入门之后便没有再刻意地去学习它了。这里就写写其中的一些关键点吧。如果我去学一门语言不是因为它火了而是我用到它了。曾经闲着没事干的时候把 Kotlin 、Vue、React…

太原计算机专业专科大学排名,太原【计算机学校】排名

太原【计算机学校】排名,资助政策1、根据国家助学金管理办法相关规定:凡被我校正式录取并注册学籍的学生在校期间均可以享受国家**费补助1900元/年,享受三年。创新科技中等专业学校排名, 有45个本科专业,16个专科专业, 3个专业硕士…

python中正则表达式的默认匹配方式为_Python模式匹配与正则表达式

1.1 不用正则表达式来匹配文本 假设我希望在一个字符串中找到电话号码,电话号码的格式为三个数字,一个短横线,四个数字,一个短横线,四个数字 比如:131-3310-5293和132-2670-9864 def IsTruePhoneNumber(con…

计算机网络应用是学什么类型的,计算机网路中服务类型及应用

服务(service)这个极普通的术语在计算机网络中无疑是一个极重要的概念。在网络体系结构中,服务就是网络中各层向其相邻上层提供的一组操作,是相邻两层之间的界面。由于网络分层结构中的单向依赖关系,使得网络中相邻层之间的界面也是单向性的&…

oschina git服务, 如何生成并部署ssh key

1.如何生成ssh公钥 你可以按如下命令来生成 sshkey: ssh-keygen -t rsa -C "xxxxxxxxxx.com" # Generating public/private rsa key pair... # 三次回车即可生成 ssh key 查看你的 public key,并把他添加到码云(Gitee.com) SSH k…

需求调研报告模板_2020年工业软管行业深度市场调研及投资策略建议报告-液体化学品增加对其需求...

(原标题:液体化学品市场规模增加 对工业软管需求量变大)工业软管,又称为工业胶管。主要用于各行业各设备作软体连接的一种软管。相比民用软管,工业作业环境更复杂、更恶劣、设备对输送管的要求也更苛刻,因此…

计算机基础理论知识的论文,计算机基础毕业论文

计算机基础毕业论文随着科学技术的不断发展,计算机也开始人类在正常生活当中所应用的一个高新的技术。下面是小编整理的计算机基础毕业论文,欢迎来参考!摘要:大学进行计算机教学能够对学生的创新能力进行培养,还能够使…

hyperledger fabric_鼎诚鬼才|超级账本入门(四):HYPERLEDGER 权限管理

权限管理权限管理机制是 hyperledger fabric 项目的一大特色。下面给出使用权限管理的一个应用案例。启动集群首先现在相关镜像。$ docker pull yeasy/hyperledger:latest $ docker tag yeasy/hyperledger:latest hyperledger/fabric-baseimage:latest $ docker pull yeasy/hyp…

Python基础检测:20171105

第一周的预习结束了 效果并不理想,最后的检测也是有个别同学表现还可以.最后一次检测,除了依旧不是放在一个文件里,文件也没有标注作者从而导致我没办法一一回复外,有些问题写的不好意外.基本没什么毛病,摔! 本次问题是以小故事的形式展开并串联的,并没有什么特殊的意思.本人不…