JavaScript之ES5的继承

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

内容简介:自从有了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的继承,麻烦太多太多,以后的实际工作也不会使用;

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


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

查看所有标签

猜你喜欢:

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

Web Data Mining

Web Data Mining

Bing Liu / Springer / 2006-12-28 / USD 59.95

Web mining aims to discover useful information and knowledge from the Web hyperlink structure, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is n......一起来看看 《Web Data Mining》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具