JavaScript面向对象轻松入门之继承(demo by ES5、ES6)

  继承是面向对象很重要的一个概念,分为接口继承和实现继承,接口继承即为继承某个对象的方法,实现继承即为继承某个对象的属性。JavvaScript通过原型链来实现接口继承、call()或apply()来实现实现继承。

  接口继承的实现在ES5中是比较麻烦,在其它OOP语言中一个extends关键字就可以实现,但在ES5中要通过原型链去模拟,非常难理解,对初学者很不友好,并且有好几种接口继承的方式。本文为了对初学者更友好,并不打算让读者了解接口继承的原理,而是直接把接口继承实现方法封装成一个函数,大家只要把这个函数拿过去用就可以了。

  相关概念:父类(超类)即为被继承者,子类(派生类)即继承者

接口继承函数extend():

 1 function extend(subClass, superClass) {
 2     function o() {
 3         this.constructor = subClass;
 4     }
 5     o.prototype = superClass.prototype;
 6     subClass.prototype = new o();
 7     return subClass.prototype;
 8 }
 9 /*
10 subClass是子类,superClass是父类,extend函数让subClass继承superClass的原型方法,并返回subClass的原型;
11 这种继承方式也是用的最多的,并且ES6的extends也是通过这种方式实现的,可以说是比较权威的用法;
12 */

ES5继承DEMO:

 1 function Animal(shoutVoice,speed){
 2     this._shoutVoice = shoutVoice;//string
 3     this._speed = speed;//string
 4 }
 5 Animal.prototype.getSpeed = function(){
 6     return this._speed;
 7 };
 8 Animal.prototype.shout = function(){
 9     console.log(this._shoutVoice);
10 };
11 Animal.prototype.run = function(){
12     console.log(‘嘿嘿,吃我灰吧!我的速度可是有‘+this._speed);
13 };
14
15 function Dog(){
16     Animal.call(this,‘汪汪汪!‘,‘10m/s‘);
17     //实现继承:调用Animal的构造函数,继承Animal类的属性,第一个参数必须是this;
18 }
19 //接口继承:extends函数让Dog类继承Animal类的的原型方法并返回Dog的新的原型prototype;
20 var DogP = extend(Dog,Animal);
21 /*可以继续给的Dog类的prototype添加方法*/
22 DogP.gnawBone = function() {
23     console.log(‘这是本狗最幸福的时候‘);
24 }
25 /*也可以把父类的方法覆盖掉*/
26 DogP.run = function(){
27     console.log(‘这是Dog类上的run方法,不是Animal类的‘);
28     /*虽然覆盖掉了,但实际上Animal类的run方法还在,也可以通过这种方式访问父类的方法,
29     对原理有兴趣的同学可以了解一下原型链*/
30     Animal.prototype.run.call(this);
31 }
32 var dog = new Dog();
33 console.log(dog.getSpeed());//log: ‘10m/s‘
34 dog.shout();//log: ‘汪汪汪!‘
35 dog.run();
36 /*log:
37 ‘这是Dog类上的run方法,不是Animal类的‘
38 ‘嘿嘿,吃我灰吧!我的速度可是有10m/s‘
39 */
40 dog.gnawBone();//log: ‘这是本狗最幸福的时候‘42 /*其它类继承Animal类*/
43 function Snake(){
44     Animal.call(this,‘嘶!嘶!嘶!‘,‘5m/s‘);
45 }
46 var SnakeP = extend(Snake,Animal);
47 /*Dog类也可以继续被继承*/
48 function PoodleDog(){
49     Dog.call(this);
50     this._breed = ‘poodle‘;
51 }
52 var PoodleDogP = extend(PoodleDog,Dog);
53 /*理论上讲可以无限继承下去,如浏览器DOM对象就继承了很多个对象,组成了一个长长的原型链
54 如一个div标签对象的类继承顺序:
55 HTMLDivElement<HTMLElement<Element<Node<EventTarget<Object
56 但我们的项目中最好别超过3次,否则就不太好控制了;*/

注意事项:

  *继承的次数不应过多,否则子类一不小心就把父类的属性方法给覆盖了;
  *我们可以把继承的对象作为成员属性,即组合,尽量少用继承,多用组合;
  *父类的属性和方法最好别太多,过多也容易被子类覆盖,可以抽象成一个对象来管理过多的属性和方法。
  *继承增加了耦合,所以父类封装性一定要好,尽量降低与子类的耦合,
  *父类的设计要有前瞻性,具备一定的扩展能力,你也不希望今后修改父类的时候,再去修改所有的子类吧?

  *父类尽量只定义方法,不定义属性,即构造函数最好是空函数;

ES6继承DEMO:

  ES6实现继承就方便很多了,由于TypeScript实现继承和ES6差不多,所以这章就不贴出TypeScript的Demo了

 1 class Animal{
 2     constructor(shoutVoice,speed){
 3         this._shoutVoice = shoutVoice;//string
 4         this._speed = speed;//string
 5     }
 6     get speed(){
 7         return this._speed;
 8     }
 9     shout(){
10         console.log(this._shoutVoice);
11     }
12     run(){
13         console.log(‘嘿嘿,吃我灰吧!我的速度可是有‘+this._speed);
14     }
15 }
16 class Dog extends Animal{
17     constructor(){
18         super(‘汪汪汪!‘,‘10m/s‘);//相当于Animal.call(this,‘汪汪汪!‘,‘10m/s‘);
19     }
20     gnawBone() {
21         console.log(‘这是本狗最幸福的时候‘);
22     }
23     run(){
24         console.log(‘这是Dog类上的run方法,不是Animal类的‘);
25         super.run();//相当于Animal.prototype.run.call(this);
26     }
27 }
28 class PoodleDog extends Dog{
29     constructor(){
30         super();
31         this._breed = ‘poodle‘;
32     }
33     get breed(){
34         return this._breed;
35     }
36 }
37 let poodleDog = new PoodleDog();
38 console.log(poodleDog.breed);//log: ‘poodle‘
39 console.log(poodleDog.speed);//log: ‘10m/s‘
40 poodleDog.shout();//log: ‘汪汪汪!‘
41 poodleDog.run();
42 /*log:
43 ‘这是Dog类上的run方法,不是Animal类的‘
44 ‘嘿嘿,吃我灰吧!我的速度可是有10m/s‘
45 */
46 poodleDog.gnawBone();//log: ‘这是本狗最幸福的时候‘

后话

  js的继承与其它OOP语言有一些不同的地方,所以最终还是要深刻的理解原型、原型链才能灵活运用,希望大家有时间一定要把这部分知识补上;

  如果你喜欢作者的文章,记得收藏,你的点赞是对作者最大的鼓励;

  作者会尽量每周更新一章,下一章是讲多态;

  大家有什么疑问可以留言或私信作者,作者尽量第一时间回复大家;

  如果老司机们觉得那里可以有不恰当的,或可以表达的更好的,欢迎指出来,我会尽快修正、完善。

时间: 2024-10-10 23:55:16

JavaScript面向对象轻松入门之继承(demo by ES5、ES6)的相关文章

JavaScript面向对象轻松入门之封装(demo by ES5、ES6、TypeScript)

本章默认大家已经看过作者的前一篇文章 <JavaScript面向对象轻松入门之抽象> 为什么要封装? 封装(Encapsulation)就是把对象的内部属性和方法隐藏起来,外部代码访问该对象只能通过特定的接口访问,这也是面向接口编程思想的一部分. 封装是面向对象编程里非常重要的一部分,让我们来看看没有封装的代码是什么样的: 1 function Dog(){ 2 this.hairColor = '白色';//string 3 this.breed = '贵宾';//string 4 this

JavaScript面向对象轻松入门之概述(demo by ES5、ES6、TypeScript)

写在前面的话 这是一个JavaScript面向对象系列的文章,本篇文章主要讲概述,介绍面向对象,后面计划还会有5篇文章,讲抽象.封装.继承.多态,最后再来一个综合. 说实话,写JavaScript面向对象的文章实在是太多了,网上一搜一大堆,很多书里面也介绍的很详细.但作者当初在学习面向对象的时候还是非常困难,特别是在习惯了面向过程编程的情况下,不知道大家有没有这个感受. 作者分析了一下其中的原因,恐怕是因为里面涉及的概念太多:原型.原型链.继承.this.constructor.call等等,这

JavaScript面向对象轻松入门之多态(demo by ES5、ES6、TypeScript)

多态(Polymorphism)按字面的意思就是"多种状态",同样的行为(方法)在不同对象上有不同的状态. 在OOP中很多地方都要用到多态的特性,比如同样是点击鼠标右键,点击快捷方式.点击桌面空白处.点击任务栏等弹出的菜单都是不同的. 方法重写(override): 即子类定义一个与父类名字相同的方法,以此覆盖父类方法,以此来实现不同的功能. 1 function Animal(){} 2 var AnimalP = Animal.prototype; 3 AnimalP.eat =

javascript面向对象系列3——实现继承的6种方式

[前面的话]许多OO语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法,由于函数没有签名,在ECMAScript中无法实现接口继承,ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的 [1][原型链继承]实现的本质是重写原型对象,代之以一个新类型的实例.实际上不是SubType的原型的constructor属性被重写了,而是SubType的原型指向了另一个对象——SuperType的原型,而这个原型对象的construtor属性

我对javascript面向对象编程的理解---------继承

要了解javascript继承首先我们了解什么是继承 继承:继承是指一个对象直接使用另一对象的属性和方法. 所及这是我们要达到的效果 先写一个父类 function Person(name,sex){ this.name = name; this.sex = sex; } Person.prototype.showName(){ alert(this.name); } Person.prototype.showSex(){ alert(this.sex); }

javascript面向对象(三)--继承

1 //继承: ECMAScript只支持 实现继承 依靠原型链来实现 2 //一.原型链 3 //先来理清下关系: 4 //每个构造函数都会有一个原型对象 Person --> prototype 5 //每一个原型对象都会有一个指向构造函数的指针 Person.prototype.constructor --> Person 6 //每一个实例都包含一个指向原型对象的内部指针 person1 --> prototype 7 //当原型对象等于另一个类的实例的时候,那么原型对象就会包含

JavaScript面向对象编程入门

来源极客网 1 function Person() { 2 var _this = {} //创建一个空的对象,接着我们利用这个"空的对象"承载Person的属性和方法 3 _this.sayHello = function(){ 4 alert("PHello"); 5 } 6 return _this; 7 } 8 9 function Teacher_1() { 10 var _this = Person();//注意这里的语法小括号 11 return _t

javascript面向对象系列5——知识点(原型和原型链)

基本概念 [原型链]每个构造函数都有一个对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针.那么,如果原型对象等于另一个原型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针.如果另一个原型又是另一个原型的实例,那么上述关系依然成立.如此层层递进,就构成了实例与原型的链条. [原型对象]这个对象包含可以由特定类型的所有实例共享的属性和方法.所有引用类型默认都继承了Object,而这个继承也是通过原型链实现

【转】「译」ES5, ES6, ES2016, ES.Next: JavaScript 的版本是怎么回事?

ES5, ES6, ES2016, ES.Next: What's going on with JavaScript versioning? Posted by Hux on September 22, 2015 JavaScript 有着很奇怪的命名史. 1995 年,它作为网景浏览器(Netscape Navigator)的一部分首次发布,网景给这个新语言命名为 LiveScript.一年后,为了搭上当时媒体热炒 Java 的顺风车,临时改名为了 JavaScript (当然,Java 和