JavaScript面向对象轻松入门之继承(demo by ES5、ES6)
继承是面向对象很重要的一个概念,分为接口继承和实现继承,接口继承即为继承某个对象的方法,实现继承即为继承某个对象的属性。JavvaScript通过原型链来实现接口继承、call()或apply()来实现实现继承。
接口继承的实现在ES5中是比较麻烦,在其它OOP语言中一个extends关键字就可以实现,但在ES5中要通过原型链去模拟,非常难理解,对初学者很不友好,并且有好几种接口继承的方式。本文为了对初学者更友好,并不打算让读者了解接口继承的原理,而是直接把接口继承实现方法封装成一个函数,大家只要把这个函数拿过去用就可以了。
相关概念:父类(超类)即为被继承者,子类(派生类)即继承者
接口继承函数extend():
function extend(subClass, superClass) {
function o() {
this.constructor = subClass;
}
o.prototype = superClass.prototype;
subClass.prototype = new o();
return subClass.prototype;
}
/*
subClass是子类,superClass是父类,extend函数让subClass继承superClass的原型方法,并返回subClass的原型;
这种继承方式也是用的最多的,并且ES6的extends也是通过这种方式实现的,可以说是比较权威的用法;
*/
ES5继承DEMO:
function Animal(shoutVoice,speed){
this._shoutVoice = shoutVoice;//string
this._speed = speed;//string
}
Animal.prototype.getSpeed = function(){
return this._speed;
};
Animal.prototype.shout = function(){
console.log(this._shoutVoice);
};
Animal.prototype.run = function(){
console.log('嘿嘿,吃我灰吧!我的速度可是有'+this._speed);
};
function Dog(){
Animal.call(this,'汪汪汪!','10m/s');
//实现继承:调用Animal的构造函数,继承Animal类的属性,第一个参数必须是this;
}
//接口继承:extends函数让Dog类继承Animal类的的原型方法并返回Dog的新的原型prototype;
var DogP = extend(Dog,Animal);
/*可以继续给的Dog类的prototype添加方法*/
DogP.gnawBone = function() {
console.log('这是本狗最幸福的时候');
}
/*也可以把父类的方法覆盖掉*/
DogP.run = function(){
console.log('这是Dog类上的run方法,不是Animal类的');
/*虽然覆盖掉了,但实际上Animal类的run方法还在,也可以通过这种方式访问父类的方法,
对原理有兴趣的同学可以了解一下原型链*/
Animal.prototype.run.call(this);
}
var dog = new Dog();
console.log(dog.getSpeed());//log: '10m/s'
dog.shout();//log: '汪汪汪!'
dog.run();
/*log:
'这是Dog类上的run方法,不是Animal类的'
'嘿嘿,吃我灰吧!我的速度可是有10m/s'
*/
dog.gnawBone();//log: '这是本狗最幸福的时候' /*其它类继承Animal类*/
function Snake(){
Animal.call(this,'嘶!嘶!嘶!','5m/s');
}
var SnakeP = extend(Snake,Animal);
/*Dog类也可以继续被继承*/
function PoodleDog(){
Dog.call(this);
this._breed = 'poodle';
}
var PoodleDogP = extend(PoodleDog,Dog);
/*理论上讲可以无限继承下去,如浏览器DOM对象就继承了很多个对象,组成了一个长长的原型链
如一个div标签对象的类继承顺序:
HTMLDivElement<HTMLElement<Element<Node<EventTarget<Object
但我们的项目中最好别超过3次,否则就不太好控制了;*/
注意事项:
*继承的次数不应过多,否则子类一不小心就把父类的属性方法给覆盖了;
*我们可以把继承的对象作为成员属性,即组合,尽量少用继承,多用组合;
*父类的属性和方法最好别太多,过多也容易被子类覆盖,可以抽象成一个对象来管理过多的属性和方法。
*继承增加了耦合,所以父类封装性一定要好,尽量降低与子类的耦合,
*父类的设计要有前瞻性,具备一定的扩展能力,你也不希望今后修改父类的时候,再去修改所有的子类吧?
*父类尽量只定义方法,不定义属性,即构造函数最好是空函数;
ES6继承DEMO:
ES6实现继承就方便很多了,由于TypeScript实现继承和ES6差不多,所以这章就不贴出TypeScript的Demo了
class Animal{
constructor(shoutVoice,speed){
this._shoutVoice = shoutVoice;//string
this._speed = speed;//string
}
get speed(){
return this._speed;
}
shout(){
console.log(this._shoutVoice);
}
run(){
console.log('嘿嘿,吃我灰吧!我的速度可是有'+this._speed);
}
}
class Dog extends Animal{
constructor(){
super('汪汪汪!','10m/s');//相当于Animal.call(this,'汪汪汪!','10m/s');
}
gnawBone() {
console.log('这是本狗最幸福的时候');
}
run(){
console.log('这是Dog类上的run方法,不是Animal类的');
super.run();//相当于Animal.prototype.run.call(this);
}
}
class PoodleDog extends Dog{
constructor(){
super();
this._breed = 'poodle';
}
get breed(){
return this._breed;
}
}
let poodleDog = new PoodleDog();
console.log(poodleDog.breed);//log: 'poodle'
console.log(poodleDog.speed);//log: '10m/s'
poodleDog.shout();//log: '汪汪汪!'
poodleDog.run();
/*log:
'这是Dog类上的run方法,不是Animal类的'
'嘿嘿,吃我灰吧!我的速度可是有10m/s'
*/
poodleDog.gnawBone();//log: '这是本狗最幸福的时候'
后话
js的继承与其它OOP语言有一些不同的地方,所以最终还是要深刻的理解原型、原型链才能灵活运用,希望大家有时间一定要把这部分知识补上;
如果你喜欢作者的文章,记得收藏,你的点赞是对作者最大的鼓励;
作者会尽量每周更新一章,下一章是讲多态;
大家有什么疑问可以留言或私信作者,作者尽量第一时间回复大家;
如果老司机们觉得那里可以有不恰当的,或可以表达的更好的,欢迎指出来,我会尽快修正、完善。
JavaScript面向对象轻松入门之继承(demo by ES5、ES6)的更多相关文章
- JavaScript面向对象轻松入门之封装(demo by ES5、ES6、TypeScript)
本章默认大家已经看过作者的前一篇文章 <JavaScript面向对象轻松入门之抽象> 为什么要封装? 封装(Encapsulation)就是把对象的内部属性和方法隐藏起来,外部代码访问该对 ...
- JavaScript面向对象轻松入门之概述(demo by ES5、ES6、TypeScript)
写在前面的话 这是一个JavaScript面向对象系列的文章,本篇文章主要讲概述,介绍面向对象,后面计划还会有5篇文章,讲抽象.封装.继承.多态,最后再来一个综合. 说实话,写JavaScript面向 ...
- JavaScript面向对象轻松入门之多态(demo by ES5、ES6、TypeScript)
多态(Polymorphism)按字面的意思就是"多种状态",同样的行为(方法)在不同对象上有不同的状态. 在OOP中很多地方都要用到多态的特性,比如同样是点击鼠标右键,点击快捷方 ...
- JavaScript面向对象轻松入门之抽象(demo by ES5、ES6、TypeScript)
抽象的概念 狭义的抽象,也就是代码里的抽象,就是把一些相关联的业务逻辑分离成属性和方法(行为),这些属性和方法就可以构成一个对象. 这种抽象是为了把难以理解的代码归纳成与现实世界关联的概念,比如小狗这 ...
- JavaScript面向对象轻松入门之综合
javascrpit面向对象之综合 这一章是对前几章的一个总结,通过一个案例来综合认识javascript面向对象的基本用法 需求: 几乎所有的web应用都需要保存数据一些到本地,那么我们就来 ...
- JavaScript面向对象编程入门
来源极客网 function Person() { var _this = {} //创建一个空的对象,接着我们利用这个"空的对象"承载Person的属性和方法 _this.say ...
- JavaScript面向对象之Prototypes和继承
本文翻译自微软的牛人Scott Allen Prototypes and Inheritance in JavaScript ,本文对到底什么是Prototype和为什么通过Prototype能实现继 ...
- JavaScript面向对象编程指南(六) 继承
第6章 继承 6.1 原型链 6.1.1原型链示例 原型链法:Child.prototype=new Parent(); <script> function Shape(){ this.n ...
- 【转】javascript面向对象编程
摘要:本文本来是想自己写的,奈何花了好长时间写好之后忘记保存,还按了刷新键,一键回到解放前,索性不写了,所以本文是转载的. 面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式,主要包括模块化. ...
随机推荐
- .net 程序集
前言:用了几天的时间把高级编程里面程序集一章看完了,原来自己只知道写代码,右键添加引用,从来也不知道操作的实质是什么,微软总是这个套路,鼠标点点就能把任务完成,这对新手友好但是对要通透了解程序执行和内 ...
- 使用fontawesome图标
我每次找图标时都是在阿里的开源图标库中找的,但是使用起来不是很方便.而我发现了fontawesome之后,觉得实在不错,所以分享给大家. 这是一些参考的文档. fontawesome下载与使用介绍 ...
- Jedis连接池使用
构建redis连接池,返还到连接池 private static JedisPool jedisPool = null; private static Jedis jedis; static { je ...
- 简易版DES加密和解密详解
在DES密码里,是如何进行加密和解密的呢?这里采用DES的简易版来进行说明. 二进制数据的变换 由于不仅仅是DES密码,在其它的现代密码中也应用了二进制数据,所以无论是文章还是数字,都需要将明文变换为 ...
- Kafka权威指南——broker的常用配置
前面章节中的例子,用来作为单个节点的服务器示例是足够的,但是如果想要把它应用到生产环境,就远远不够了.在Kafka中有很多参数可以控制它的运行和工作.大部分的选项都可以忽略直接使用默认值就好,遇到一些 ...
- 学习MVC之租房网站(八)- 前台注册和登录
在上一篇<学习MVC之租房网站(七)-房源管理和配图上传>完成了在后台新增.编辑房源信息以及上传房源配图的功能.到此后台开发便告一段落了,开始实现前台的功能,也是从用户的登录.注册开始. ...
- Servlet,过滤器,监听器,拦截器的区别
1.过滤器 Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码.做一些业务逻辑判断等.其工作原理是,只要你在web.xml ...
- 个人对于epollhup的理解
1.原因 由于最近对于异步connect函数的测试,发现提前将一个套接字加入epoll监听队列会不断爆出epollhup事件 2.示例 ........ iEpoll = epoll_create( ...
- dubbo高级配置学习
启动时检查 可以通过check="false"关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动. 关闭某个服务的启动时检查:(没有提供者时报错) < ...
- Python装饰器实现几类验证功能做法
最近新需求来了,要给系统增加几个资源权限.尽量减少代码的改动和程序的复杂程度.所以还是使用装饰器比较科学 之前用了一些登录验证的现成装饰器模块.然后仿写一些用户管理部分的权限装饰器.比如下面这种 de ...