JS类继承常用方式发展史
JS类继承常用方式发展史
涉及知识点
前言
当JS被创造出来的时候,并没有使用当时最流行的类方式,像(JAVA C++)。具体原因为:
对于有基于类的语言经验的开发人员来说,JavaScript 有点令人困惑 (如Java或C ++) ,因为它是动态的,并且本身不提供一个类实现。(在ES2015/ES6中引入了class关键字,但只是语法糖,JavaScript 仍然是基于原型的)。
参考2
1 构造函数方式继承
1.1 通过构造函数多步骤完成继承单个对象
/**
* log-console.log的简单封装插件
*
* @demo log(xxx) ==> console.log(xxx)
* @explain 1 可以代替console.log()使用
* @explain 2 可以运行在浏览器环境和NodeJs环境
*/
function log() {
console.log.apply(console, arguments);
}
/**
* Student--学生抽象类-希望作为其中的一个父类
* @param {String} guide 职业
*/
function Student({guide}) {
this.guide = guide;
}
Student.prototype.showGuide = function() {
log(this.guide);
}
/**
* People--子类,希望能够继承Student
*
* @want People的实例对象拥有Student的特性,且可以自己扩展
* 扩展后不影响Student
*/
function People(props) {
Student.call(this, props);
this.country = props.country;
}
/**
* 通过中间对象(函数)来实现People正确的原型链指向
*
* @explain step1 MidFn 创建一个空函数
* @explain step2 把MidFn函数的原型指向Student.prototype
* @explain step3 把People原型对象指向MidFnde原型对象, MidFn的原型正好指向Student.prototype
* @explain step4 把People原型的构造函数修复为People
* @explain step5 People扩展方法测试是否会影响Student
*/
// step1
function MidFn() {}
// step2
MidFn.prototype = Student.prototype;
// step3
People.prototype = new MidFn();
// step4
People.prototype.construtor = People;
// step5
People.prototype.showCountry = function() {
log(this.country);
}
const jeson = new People({
guide: 'web前端',
country: '中国'
});
jeson.showGuide();
jeson.showCountry();
log(jeson instanceof People); // => true
log(jeson instanceof Student); // => true
const student1 = new Student({
guide: '全栈',
country: 'Chinese'
});
student1.showGuide(); // => '全栈'
student1.showCountry(); // => 出错
分析 back
- 1 通过创建一个中间对象函数,想办法将原型链修改为:
new People() ----> People.prototype ----> Student.prototype ----> Object.prototype ----> null
参考1 - 2 为什么不只使用People.prototype = Student.prototype方式?
- 答:这个方法简单粗暴也是可以使用的,为什么不使用呢?1 耦合性太高了,修改其中的一个类,另一个也会受影响,而且如果不知道Student.showGuide方法存在,子类写了这个方法,那么恭喜,Student.prototype.showGuide方法会被子类的People.prototype.showGuide替换掉,2 为了解耦(追求更好的方式--提高编程水平)
- 3 子类的构造函数里面 父类.call(this, param1, param2)是为了实例化子类的时候将参数传给父类
1.2 封装多步骤完成继承单个对象
/**
* inherits 封装继承的动作到inherits函数,简化代码,美化世界
* @explain 通过封装4步骤完成继承
*/
function inherits(Child, Parent) {
const MidFn = function() {}
MidFn.prototype = Parent.prototype;
Child.prototype = new MidFn();
Child.prototype.construtor = Child;
}
/**
* 执行继承函数实现原型继承链
*/
inherits(People, Student);
分析 back
- 1 封装继承的多步骤为一个inherits函数,简化代码参考1
1.3 Object.create()方式完成继承单个对象
/**
* inherits 封装继承的动作到inherits函数,简化代码,美化世界
* @explain 通过Object.create实现继承
*/
function inherits(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
/**
* 执行继承函数实现原型继承链
*/
inherits(People, Student);
分析 back
- 1 通过ES5提供的Object.create()完成继承
- 2 由于new后生成的实例对象是对象(键值对),实例对象通过其构造函数的原型对象继承属性。而Object.create()可以完成对象的扩展参考3
2 继承多个对象
2.1 Object.create() Object.assign() 遍历复制实现多个对象继承
/**
* Student--学生类,作为People的一个父类
* @class
* @param {*} guide 职业
*/
function Student(props) {
this.guide = props.guide;
this.class = props.class;
}
Student.prototype.showGuide = function() {
log(this.guide);
}
/**
* Sex--性别类,作为People的一个父类
* @class
* @param {*} sex 性别
*/
function Sex({sex}) {
this.sex = sex;
}
Sex.prototype.showSex = function() {
log(this.sex);
}
/**
* People--人类--子类(想继承Student和Sex)
*
* @want People的实例对象拥有Student Sex的特性,且可以自己扩展
* 扩展后不影响Student和Sex
*/
function People(props) {
Student.call(this, props);
Sex.call(this, props);
this.country = props.country;
}
/**
* 多个对象的继承
* @param {Constrctor} Children 需要继承多个类的构造函数-这里为People
* @param {Json} Parents 多个需要被继承的构造函数
* @explain 1 实例化构造函数得到的实例对象是{...} 这种类型的对象和JSON结构一样
* @explain 2 Object.assign(target, ...sources) 通过ES5提供的复制可枚举对象实现
*/
function inheritMore(Children, ...Parents) {
// console.log(Parents);
objAssigns(Children, Parents);
Children.prototype.constrctor = Children;
}
/**
* objAssigns 继承多个对象
*
* @param Children 需要继承多个类的构造函数-这里为People
* @param {Array} Parents 多个需要被继承的构造函数构成的对象
*/
function objAssigns(Children, Parents) {
for (let i =0; i < Parents.length; i++) {
Object.assign(Children.prototype, Parents[i].prototype);
}
}
inheritMore(People, Student, Sex);
const jeson = new People({
guide: 'web前端',
country: '中国',
sex: '男',
class: '3-6'
});
People.prototype.showCountry = function() {
log(this.country);
}
jeson.showGuide(); // => 'web前端'
jeson.showSex(); // => '男'
jeson.showCountry(); // => '中国'
log(jeson instanceof Student); // => false
log(jeson instanceof Sex); // => false
log(jeson instanceof People); // => true
/**
* 父类扩展看子类是否继承
*/
Student.prototype.showClass = function() {
log(this.class);
}
let tom = new People({
class: '6-6'
})
Object.assign(People.prototype, Student.prototype); // 加上这句才能继承到父类扩展后的方法
tom.showClass(); // => '6-6'
分析 back
- 1 通过遍历多次Object.assin()完成多个对象的继承 参考4
- 2 是否可以通过多次创建空函数的方式实现多对象继承呢?实际是不可以的,子类的原型对象只会为最后一个类的实例对象,前面都被覆盖了,具体请看参考6
- 3 (优化)这种方式在继承父对象后,如果父对象扩展了某个方法,子对象需要再次继承,是否可以自动继承父类扩展的方法,不用再次继承父类呢?知道的道友可以留言
参考资料
- 参考1-廖雪峰JS-原型继承
- 参考2--构造函数原型介绍
- 参考3--Object.create()介绍
- 参考4--Object-assign()介绍
- 参考5-JS实现继承的几种方式
- 参考6-key in 方式实现多继承
JS类继承常用方式发展史的更多相关文章
- Js 类继承 extends
html 及 js 代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...
- js实现继承的方式总结
js实现继承的5种方式 以下 均为 ES5 的写法: js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承 ...
- js对象的几种创建方式和js实现继承的方式[转]
一.js对象的创建方式 1. 使用Object构造函数来创建一个对象,下面代码创建了一个person对象,并用两种方式打印出了Name的属性值. var person = new Object(); ...
- JS对象创建常用方式及原理分析
====此文章是稍早前写的,本次属于文章迁移@2017.06.27==== 前言 俗话说"在js语言中,一切都对象",而且创建对象的方式也有很多种,所以今天我们做一下梳理 最简单的 ...
- js的继承实现方式
1. 使用call或者apply来实现js对象继承 function Animal(age){ this.age = age; this.say = function(){ console.log(' ...
- js实现继承的方式
[原文] 前言 JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一.那么如何在JS中实现继承呢?让我们拭目以待. JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如下: // ...
- js 类继承extends
先看例子: <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <titl ...
- js类继承扩展super
相应的资料https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/super 例子: class Pol ...
- smartjs 0.2 OOP讲解 - Klass 类继承
SmartJS2.0加入OOP的功能.OOP包括klass与factory两个对象. Klass 类继承 与其他的类继承相比,smartjs使用了执行指针的概念(后面例子中会介绍),另外提供base基 ...
随机推荐
- MySQL的JOIN(三):JOIN优化实践之内循环的次数
这篇博文讲述如何优化内循环的次数.内循环的次数受驱动表的记录数所影响,驱动表记录数越多,内循环就越多,连接效率就越低下,所以尽量用小表驱动大表.先插入测试数据. CREATE TABLE t1 ( i ...
- 数据绑定技术一:GridView控件
在网站或应用程序中,要显示数据信息,可用到ASP.NET提供的数据源控件和能够显示数据的控件. 一.数据源控件 数据源控件用于连接数据源.从数据源中读取数据以及把数据写入数据源. 1.数据源控件特点 ...
- 团队作业8——第二次项目冲刺(Beta阶段)第三天
BETA阶段冲刺第三天 1.当天站立式会议 2.每个人的工作 (1)昨天已完成的工作: 编写页面讨论 (2)今天计划完成的工作: 完成编写页面 (3)工作中遇到的困难: 验证码正确度 (4)每个人的贡 ...
- 团队作业4——第一次项目冲刺(Alpha版本)2017.4.22
昨天来不及编写,这是4月22日的日志,现在补上. 1.开完站立式会议后的合照 2.任务分解图 3.开会讨论的结果,任务分派 队员 今日进展 明日安排 陈鑫龙 原型设计图分析,设计登陆界面原稿 实现登陆 ...
- 201521123011 《Java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 答:1.super() 子类不能继承父类的构造方法,但可以通过super关键字去访问父类的构 ...
- 201521123062《Java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 多态定义:同种形态不同定义 类注释格式 继承,共同行为及属性 在instanceof检查过后 ...
- 第2周作业-Java基本语法与类库
1. 本周学习总结 答:① 定义流程控制的各种条件式是同以前学习的一样,要善于运用快捷键.(例如`a/t` + `/` ) ② 熟悉输入输出的使用,注意输入的变量类型使用相应的输入类. ③ 数组对象: ...
- Git与码云(Git@OSC)入门-如何在实验室和宿舍同步你的代码(2)
4. 处理冲突 4.1 向远程仓库push时无法提交成功,提示在push前应该先pull 如图所示: 有可能是因为远程仓库的版本与本地仓库的版本不一致,所以应先git pull将远程仓库的内容合并到本 ...
- 201521123038 《Java程序设计》 第十周学习总结
201521123038 <Java程序设计> 第十周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题 ...
- Nim函数调用的几种形
Nim函数调用的几种形式 Nim 转载条件:如果你需要转载本文,你需要做到完整转载本文所有的内容,不得删改文内的作者名字与链接.否则拒绝转载. 关于nim的例行介绍: Nim 是一门静态编译型的系统级 ...