聊一聊各种继承方式的前世今生
目录
- 类式继承
- 优点
- 缺点
- 备注
- 构造函数继承
- 优点
- 缺点
- 备注
- 组合继承
- 优点
- 缺点
- 备注
- 原型继承
- 特点
- 备注
- 寄生继承
- 特点
- 备注
- 寄生组合继承
- 特点
- 备注
- 总结
阅读目标
- 掌握JS6大继承方式及其优缺点
- 了解各种继承方式的演变
类式继承
// 父类
function Parent(name, houses) {this.name = name;this.houses = houses;
}
Parent.prototype.getName = function() {console.log(this.name);
}
Parent.prototype.getHouses = function() {console.log(this.houses);
}// 子类
function Son() {}/*==== 核心代码 ====*/
Son.prototype = new Parent('Mark', ['北京']);const son1 = new Son();
son1.houses.push('上海');
son1.name = '斯特里';
son1.getName() // 斯特里
son1.getHouses(); // ['北京','上海']const son2 = new Son();
son2.getName() // Mark
son2.getHouses(); // ['北京','上海']
优点
- 可复用父类属性
缺点
- 父类引用属性会被共享
- 子类构建实例时不可向父类传递参数
- 子类的constructor属性被修改(不影响,可忽略)
备注
该方式的本质就是修改子类的原型对象,没什么可聊的
构造函数继承
// 父类
function Parent(name, houses) {this.name = name;this.houses = houses;
}
Parent.prototype.getName = function() {console.log(this.name);
}
Parent.prototype.getHouses = function() {console.log(this.houses);
}
// 子类
function Son(name, houses) {/*==== 核心代码 ====*/Parent.call(this, name, houses);
}const son1 = new Son('斯特里', ['北京']);
son1.houses.push('上海');
console.log(son1.name); // 斯特里
console.log(son1.houses); // [ '北京', '上海' ]
son1.getHouses || console.error('getHouses不存在'); // getHouses不存在const son2 = new Son('Mark', ['北京']);
console.log(son2.name); // Mark
console.log(son2.houses); // ['北京']
son2.getHouses || console.error('getHouses不存在'); // getHouses不存在
优点
- 父类引用属性不会被共享
- 子类构建时可向父类传递参数
缺点
- 无法继承父类原型链上的属性
备注
- 该方式简单粗暴的理解如下:每次创建子类对象的同时会创建一个父类对象,并将父类对象上的属性绑定到子类对象的上下文(this)上。
- 再认真观察之前两种继承方式的优缺点,发现彼此的优点正好可以弥补对方的缺点,由此衍生出第三种继承方式,组合继承。
组合继承
function Parent(name, houses) {this.name = name;this.houses = houses;
}
Parent.prototype.getName = function() {console.log(this.name);
}
Parent.prototype.getHouses = function() {console.log(this.houses);
}function Son(name, houses) {/*==== 构造函数继承核心代码 ====*/Parent.call(this, name, houses);
}
/*==== 类式继承核心代码 ====*/
Son.prototype = new Parent();const son1 = new Son('斯特里', ['北京']);
son1.houses.push('上海');
son1.getName(); // 斯特里
son1.getHouses(); // [ '北京', '上海' ]const son2 = new Son('富贵', ['北京']);
son2.getName(); // 富贵
son2.getHouses(); // [ '北京' ]
优点
- 可复用父类属性
- 父类引用属性不会被共享
- 子类构建实例时可以向父类传递参数
缺点
- 会调用两次父类的构造函数
备注
怎么还有缺点,不着急后续还有解决方案
原型继承
function Book() {this.name = 'Js book';this.alikeBook = ['css book'];
}
Book.prototype.getName = function() {console.log(‘getName执行了’);
}
/*==== 核心函数 ====*/
function inheritObject(SubClass) {function F() {} // 子类;F.prototype = SubClass.prototype;return new F();
}let newBook = inheritObject(Book);
newBook.getName(); // getName执行了
console.log(newBook.name); // undefined
特点
- 见名知意,该方式可以仅仅继承父类上的原型属性,不继承父类本身的属性
备注
- 该继承其实就是类式继承的一次改造
- 乍一看,特别容易得出一种结论:这不就是封装了一下原型模式么。但当认真分析函数后会发现,这种继承方式其实是在原型继承基础上有选择的继承了父类原型上的内容
寄生继承
/*==== 原型继承核心 ===*/
function inheritObject(o) {function F() {};F.prototype = o;return new F();
}
/*==== 寄生继承核心 ====*/
function createBook(obj) {const o = inheritObject(obj);o.getName = function() {console.log(this.name);}return o;
}let book = {name: 'Js book',alikeBook: ['css book'],
}let newBook = createBook(book);
newBook.name = 'Ajax book';
newBook.alikeBook.push('xml book');
newBook.getName(); // Ajax book
console.log(newBook.alikeBook); // [ 'css book', 'xml book' ]let otherBook = createBook(book);
otherBook.name = 'flash book';
otherBook.getName(); // flash book
console.log(otherBook.alikeBook); // [ 'css book', 'xml book' ]
特点
- 对原型继承产生的对象进行扩展
备注
- 该继承其实就是原型继承的一次改造, 寄生继承是的寄生对象是原型继承的产物
- 在此我们观察
inheritObject
函数,每次使用寄生继承都会创建一个空函数F,这样有些浪费内存,此时可以将该函数做成一个单例函数F以避免频繁创建,当完成这一步,我们便实现了ES6中Object.crate()方法
寄生组合继承
/*==== 原型继承核心 ====*/
function inheritObject(o) {function F() {}F.prototype = o;return new F();
}
/*==== 寄生继承核心 ====*/
function inheritPrototype(subClass, superClass) {let p = inheritObject(superClass.prototype);p.constructor = subClass; // 纠正子类constructor的指向subClass.prototype = p;
}function SuperClass(name) {this.name = name;this.colors = ['red', 'blue', 'green'];
}SuperClass.prototype.getName = function() {console.log(this.name);
}function SubClass(name, time) {/*==== 构造函数继承核心 ====*/SuperClass.call(this, name);this.time = time;
}inheritPrototype(SubClass, SuperClass);let instance1 = new SubClass('Js book', 2014);
let instance2 = new SubClass('css book', 2013);
console.log(instance1.colors);
console.log(instance2.colors);
instance2.getName();
特点
- 解决了组合继承中父类构造函数会调用两次的问题
备注
- ES6中的
class
继承就是该继承方式的一种语法糖 - 该继承是寄生寄生和组合继承的的融合,通过寄生继承中只操作原型的方式实现原型继承,而不是类式继承中创建对象的方式,从而避免了父类构造函数调用两次的问题
总结
其实分析前五种继承方式的过程就是寄生组合继承的推导过程,推导过程如下:
聊一聊各种继承方式的前世今生相关推荐
- php中 继承中的概念,JavaScript_JavaScript中的继承方式详解,js继承的概念
js里常用的如下 - phpStudy...
JavaScript中的继承方式详解 js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于 ...
- JavaScript之各种继承方式和优缺点
2019独角兽企业重金招聘Python工程师标准>>> JavaScript之各种继承方式和优缺点 原型链继承 function Parson(){this.name = 'hy' ...
- C++中不同的继承方式
文章目录 1 C++中不同的继承方式 1.1 继承中被忽视的细节 1.2 不同的继承方式 1.3 继承中只选择public继承 1 C++中不同的继承方式 1.1 继承中被忽视的细节 如下: 1.2 ...
- 派生类的继承方式【C++继承】
类别 public protected private 派生类成员标识 图示(表格/图) 分类(四类访问) 类的作用域运算 Shadow 作用域运算符:: 小结 why public? 继承方式 继承 ...
- javascript中的继承方式
javascript中的继承方式有好几种. 下面分别举例供大家参考学习: 1.function parent() { this.x=1; } function child() { var instan ...
- 关于继承方式和访问权限
注:本文摘自unixfy博文,感谢作者整理! 关于访问控制权限和继承方式 关于访问权限和继承方式 访问权限有三种:public.protected.private 继承也有三种:public.prot ...
- 在保护继承中基类的共有成员_C++学习大纲:继承方式的调整
C++ 继承方式的调整 在任何继承方式中,除了基类的private成员外,都可以在派生类中分别调整其访问控制. 调整格式 [public: | protected: | private: ] :: ; ...
- C++继承的继承方式
继承方式一共有三种: 1.公共继承 2.保护继承 3.私有继承
- c++中的继承--1(引出,继承方式,继承的对象模型)
继承的引出 概念: 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加功能,这样产生新的类,称派生类.继承呈现了面向 ...
最新文章
- 西班牙放大招,利用区块链技术防腐
- 使用C++实现Socket编程传输文件
- 性感的CSS Menus
- leetcode day2 -- Sort List Insertion Sort List
- Centos 利用yum源安装 nginx 1.20.1
- flash大作业一分钟源文件_初中生写作业慢的7个原因及对策
- AppScan api登录接口 postman_如何通过Postman调用EDI系统的API?
- 用C语言实现回调函数
- JAVA中各种简写全称整理
- 【转】飞鸽端口号被占用时的解决方法
- BUUCTF-Crypto-rabbit+篱笆墙上的影子(栅栏密码)+RSA题解
- 江苏省2021年高考成绩查询入口,江苏省教育考试院2021年江苏高考成绩查询时间及系统入口【预计6月24日起查分】...
- 规范的计算机网络规模分类,就计算机网络按规模分类而言,下列说法中规范的是( )。...
- mysql oracle minus_Oracle minus使用
- macos的pycharm无setting选项
- Centos7安装JDK【FinalShell终端本地文件上传失败解决办法】
- 转载:24岁了,做个精致的电子工程师
- mysql安装时的英文_安装MySQL遇到的常见英文翻译
- 网络栈主要结构介绍(socket、sock、sk_buff,etc)
- 进入3.0时代,紫光云致力做好数字化转型的底座