• JavaScript之ES5的继承


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

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

  • 相关阅读:
    redis 布隆过滤器
    ltp分词加入词典后处理——强制分词
    python零散的小知识点
    icecream调试
    pandas操作excel的基础知识
    Neo4j在python中的基础操作
    正则表达式中的split的使用
    初始化方法__init__
    if语句中的多个条件**的并与交
    python爬虫
  • 原文地址:https://www.cnblogs.com/cpfblogs/p/12906299.html
Copyright © 2020-2023  润新知