Js继承的实现方式
时间:2022-07-24
本文章向大家介绍Js继承的实现方式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Js继承的实现方式
继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。
原型链继承
通过将子类的原型对象指向父类的实例,实现继承访问父类属性方法等
// 定义父类
function Parent(){
this.name = "parent";
this.say = function(){
console.log(this.name);
}
}
// 定义子类
function Child(){
this.name = "child";
}
Child.prototype = new Parent(); // 将子类的原型对象指向父类的实例
Child.prototype.construce = Child; // 修复constructor使符合原型链规定
var child = new Child(); // 实例化子类
child.say(); // child // 此时子类能够访问父类的say方法,在查找name属性的时候首先在自身属性中查找成功所以不再向上查找,若子类没有name成员,则会打印parent
console.log(child instanceof Parent); // true // 判断child的构造函数Child的prototype对象是否在Parent的原型链上
特点
- 父类新增原型方法与属性,子类都能访问到
- 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
- 子类实例可以继承父类构造函数属性和方法、父类原型属性和方法
不足
- 无法实现多继承
- 子类实例化时无法向父类的构造函数传参
- 所有子类实例都会共享父类的原型对象中的属性
构造函数继承
当子类构造函数被调用时,借助call
或者apply
调用父类构造方法实现对于this
的拓展
// 定义父类
function Parent(from){
this.name = "parent";
this.say = function(){
console.log(this.name);
}
this.from = from;
}
// 定义子类
function Child(from){
Parent.call(this, from); // 调用父类构造函数并绑定this来拓展Child实例成员方法,可以传递参数
this.name = "child";
}
var child = new Child("child"); // 实例化子类
child.say(); // child
console.log(child.from); // child
特点
- 子类实例不会共享父类属性方法
- 实例化子类时可以向父类构造函数传参
- 通过调用多个父类构造函数可以实现多继承
不足
- 实例并不是父类的实例,只是子类的实例
- 只继承了父类的构造函数的属性和方法,没有继承父类原型的属性和方法
- 每个子类都有父类实例函数的副本,拷贝了父类函数而不是引用,影响性能
实例继承
为父类实例增加成员与方法,作为实例返回
// 定义父类
function Parent(from){
this.name = "parent";
this.say = function(){
console.log(this.name);
}
this.from = from;
}
// 定义子类
function Child(from){
var instance = new Parent(from);
instance.name = "child";
return instance;
}
var child = new Child("child"); // 实例化子类
child.say(); // child
console.log(child.from); // child
特点
- 实例化子类时可以向父类构造函数传参
- 子类的实例化方式可以为
new Child()
或直接调用Child()
不足
- 不支持多继承
- 实例是父类的实例,不是子类的实例
- 同样也是将父类的成员与方法做了实例化拷贝
拷贝继承
通过直接将父类的属性拷贝到子类的原型中实现继承
// 定义父类
function Parent(from){
this.name = "parent";
this.say = function(){
console.log(this.name);
}
this.from = from;
}
// 定义子类
function Child(from){
var instance = new Parent(from);
for(let item in instance) Child.prototype[item] = instance[item];
this.name = "child";
}
var child = new Child("child"); // 实例化子类
child.say(); // child
console.log(child.from); // child
特点
- 支持多继承
- 实例化子类时可以向父类构造函数传参
不足
- 无法获取父类不可枚举的方法
- 同样也是将父类的成员与方法做了实例化并拷贝
原型式继承
通过共享原型对象实现继承
// 定义父类
function Parent(){}
Parent.prototype.name = "parent";
Parent.prototype.say = function(){ console.log(this.name); }
// 定义子类
function Child(from){
this.name = "child";
}
Child.prototype = Parent.prototype; // 共享原型
Child.prototype.construce = Child;
var child = new Child("child"); // 实例化子类
child.say(); // child
特点
- 实现了方法与属性的复用
- 父类新增原型方法与属性,子类都能访问到
不足
- 不能继承父构造函数的实例对象的成员
- 所有子类实例都会共享父类的原型对象中的属性
组合继承
组合原型链继承和借用构造函数继承,结合了两种模式的优点,传参和复用
// 定义父类
function Parent(from){
this.name = "parent";
this.say = function(){
console.log(this.name);
}
this.from = from;
}
// 定义子类
function Child(from){
Parent.call(this, from);
this.name = "child";
}
Child.prototype = new Parent();
Child.prototype.construce = Child;
var child = new Child("child"); // 实例化子类
child.say(); // child
console.log(child.from); // child
特点
- 原型方法可以复用
- 既是子类的实例,也是父类的实例
- 实例化子类时可以向父类构造函数传参
- 可以继承实例属性和方法,也可以继承原型属性和方法
不足
- 调用了两次父类构造函数,生成了两份实例,子类的构造函数的拷贝会代替原型上的父类构造函数的实例
寄生组合继承
通过寄生方式,砍掉父类的实例属性,在调用两次父类的构造的时候,就不会初始化两次实例方法和属性,避免的组合继承的缺点
// 定义父类
function Parent(from){
this.name = "parent";
this.say = function(){
console.log(this.name);
}
this.from = from;
}
// 定义子类
function Child(from){
Parent.call(this, from);
this.name = "child";
}
var f = function(){}; // 创建一个没有实例方法的类
f.prototype = Parent.prototype; // 浅拷贝父类原型
Child.prototype = new f(); // 实例化f,此时没有实例化方法调用,同时将原型链建立
Child.prototype.construce = Child;
var child = new Child("child"); // 实例化子类
child.say(); // child
console.log(child.from); // child
特点
- 比较完善
不足
- 相对比较复杂
参考
https://www.jianshu.com/p/b76ddb68df0e
https://www.cnblogs.com/ranyonsue/p/11201730.html
https://www.cnblogs.com/humin/p/4556820.html#!comments
- 使用javascript+xml实现分页
- 使用OAuth打造webapi认证服务供自己的客户端使用
- 洛谷P3381 【模板】最小费用最大流(dijstra费用流)
- 使用OAuth打造webapi认证服务供自己的客户端使用(二)
- JavaScript基础1
- JavaScript实例-----反选
- 1303: [CQOI2009]中位数图
- 1050: [HAOI2006]旅行comf
- 某厂2016实习招聘安全技术试题答案及解析
- 3732: Network
- 洛谷P3388 【模板】割点(割顶)(tarjan求割点)
- 每天学一点Docker(3)(制作你的第一个容器)
- 1635: [Usaco2007 Jan]Tallest Cow 最高的牛
- 1653: [Usaco2006 Feb]Backward Digit Sums
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 消息队列的消费幂等性如何保证
- js中数组Array.reduce方法介绍及使用场景
- 推荐一套基于go开发的文档管理系统
- 如何通过容器搭建稳定可靠的私有网盘(NextCloud)
- Flutter实现倒计时功能
- Excelize 2.3.0 发布, Go 语言 Excel 基础库
- 网站渗透攻防Web篇之SQL注入攻击高级篇
- 网站渗透攻防Web篇之SQL注入攻击中级篇
- Go 语言学习之 method
- 网站渗透攻防Web篇之SQL注入攻击初级篇
- VBA解析复合文档05——读取数据流
- C++核心准则E.25:如果不能抛出异常,模仿RAII方式进行资源管理
- VBA解析复合文档06——改写数据流
- PyTorch5:torch.nn总览&torch.nn.Module
- 玩转Spring中强大的spel表达式!