JavaScript之ES5的继承

栏目: IT技术 · 发布时间: 4年前

内容简介:自从有了ES6的继承后,ES5的继承也退出了舞台,在实际开发也不会用得着,但在面试或许用的着;先看看ES6的继承在ES6里只需要使用extends和super关键字即可继承父类的方法和属性(包括静态)

自从有了ES6的继承后,ES5的继承也退出了舞台,在实际开发也不会用得着,但在面试或许用的着;

先看看ES6的继承

 1 class Father{
 2             
 3             constructor(a){
 4                 console.log(a);
 5             }
 6             play(){
 7                 console.log("aaa");
 8             }
 9             static run(){
10                 console.log("static");
11             }
12         }
13         class Son extends Father{
14             constructor(){
15                 super();
16             }
17         }
18         var s=new Son();
19         s.play();
20         Father.run()
21         Son.run();

在ES6里只需要使用extends和super关键字即可继承父类的方法和属性(包括静态)

在ES5里没有这些关键字

ES5的继承

ES5的五种种继承方式:

  1. 对象冒充继承
  2. 原型链继承
  3. 组合继承
  4. 原型式继承
  5. 寄生式继承(重要)
  • 对象冒充继承
1 function Father(_r){
 2             this.r=_r;
 3             console.log("aa");
 4             console.log(this.r);
 5         }
 6         Father.a=3;
 7         Father.run=function(){
 8             console.log(Box.a);
 9         }
10 function Son(){
11             Father.call(this,3);//改变this的指向,执行父类构造函数并传参到父类
12        }
13        var b=new Son();//"aa",3
14        b.run();//TypeError

通过call或apply改变this指向,并执行了父类的构造函数

缺点:只能继承超类的构造函数,无法继承原型链上的方法

  • 原型链继承
 1 function Father(){
 2     console.log("aa");
 3         }
 4 Father.prototype.b=10;
 5         Father.prototype.play=function(){
 6             console.log(this.b);
 7         }
 8         Son.prototype=new Father();
 9         function Son(){
10         }        
11         var b=new Son();
12         b.play();//10

将父类的实例化对象赋值给子类的原型上实现的继承

缺点:覆盖子类原有的属性和方法,只能执行父类的属性和方法,无法执行父类的构造函数

  • 组合继承

前面的两种继承(冒充,原型链)各有特点,把这两种继承组合起来称为组合继承

 1  function Father(_r){
 2             this.r=_r;
 3             console.log("aa");
 4         }
 5 function Son(_r){
 6             Father.call(this,_r);//冒充,改变父类的this指向子类
 7         }
 8 Son.prototype=new Father(3);//原型链继承
 9  var c=new Son(10);
10  

使用原型链继承了父类的属性和方法,使用对象冒充继承了父类的构造函数

看起来很不错的样子,但这并不是完美的继承方式;

缺点:会覆盖子类原有的属性和方法,因为原型链继承会将父类实例化,提前执行了一次父类构造函数;当子类实例化对象后,实际上是执行了两次父类的构造函数。

使用场景:子类原本没有属性和方法,父类构造函数没有内容。

  • 原型式继承

为了解决执行两次父类构造函数使用了一个中介,在继承时就不会执行父类的构造函数

 1 function Father(_a){
 2             this.a=_a
 3         }
 4         Father.prototype.play=function(){
 5             console.log("aaa");
 6         }
 7             function Agent(){
 8 
 9             }
10             Agent.prototype=Father.prototype;
11             function Son(){
12                 
13             }
14             Son.prototype=new Agent();
15             var o=new Son();
16             o.play();//aaa

使用了Agent的类作为中介,将父类的原型复制后,再进行实例化继承不会执行父类的构造函数;

缺点:虽然解决了构造函数执行两次的问题,但是使用该方法继承后,构造函数一次也不会执行。

  • 寄生式继承(完美继承)

封装了一个extend方法,该方法传入两个参数,分别是父类和子类

 1 function extend(subClass, supClass) {
 2         function Agent() {}
 3         Agent.prototype = supClass.prototype;
 4         var o = subClass.prototype;
 5         subClass.prototype = new Agent();
 6         if (Object.assign) {
 7           Object.assign(subClass.prototype, o);
 8         } else {
 9           if (Object.getOwnPropertyNames) {
10             var names = Object.getOwnPropertyNames(o);
11             for (var i = 0; i < names.length; i++) {
12               var desc = Object.getOwnPropertyDescriptor(names[i]);
13               Object.defineProperty(subClass.prototype, names[i], desc);
14             }
15           } else {
16             for (var prop in o) {
17               subClass.prototype[prop] = o[prop];
18             }
19           }
20         }
21         subClass.prototype.constructor = subClass; //防止子类的构造函数被覆盖
22         if (supClass.prototype.constructor === Object) {
23           supClass.prototype.constructor = supClass; //防止父类类的构造函数被覆盖
24         }
25         // 存储父类,方便继承构造函数调用
26         subClass.prototype.superClass = supClass;
27       }
28 //调用
29       function Father(_r) {
30         this.r = _r;
31         console.log("Father");
32       }
33       Father.prototype.play = function () {
34         console.log("play game");
35       };
36       function Ball(_r) {
37         this.superClass.call(this, _r);
38       }
39 40       var s = new Son(10);//Father
41       s.play();//play game

extend方法,使用了Object.assgin、Object.getOwnPropertyNames、Object.getOwnPropertyDescriptor、Object.defineProperty都存在兼容问题,所以进行了判断。

该方法继承集合了前四种的优点,实现了ES5的完美继承;

结语:

ES5对比ES6的继承,麻烦太多太多,以后的实际工作也不会使用;

但是在面试的时候,面试官可能会问,多学一点总没错。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

利用Python进行数据分析

利用Python进行数据分析

Wes McKinney / 唐学韬 / 机械工业出版社 / 2013-11-18 / 89.00

【名人推荐】 “科学计算和数据分析社区已经等待这本书很多年了:大量具体的实践建议,以及大量综合应用方法。本书在未来几年里肯定会成为Python领域中技术计算的权威指南。” ——Fernando Pérez 加州大学伯克利分校 研究科学家, IPython的创始人之一 【内容简介】 还在苦苦寻觅用Python控制、处理、整理、分析结构化数据的完整课程?本书含有大量的实践案例,......一起来看看 《利用Python进行数据分析》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具