zoukankan      html  css  js  c++  java
  • js 中继承方式小谈

    题外话

    前段时间面试中笔试题有这道题目:
    请实现一个继承链,要求如下:

    • 构造函数A():构造函数中有consoleA方法,可以实现console.log("a")
      实例对象 a:a 可以调用consoleA方法

    • 构造函数B():构造函数中有consoleB方法,可以实现console.log("b")
      实例对象 b:b 可以调用consoleAconsoleB方法

    • 构造函数C():构造函数中有consoleC方法,可以实现console.log("c")
      实例对象 c:c 可以调用consoleAconsoleBconsoleB方法

    ok,这个题目暂时搁置,再回到这个问题之前,我们先来看看 js 的继承方式

    约定

    // 父类
    function Super() {
      this.name = "parent0";
      this.colors = ["red", "blue", "yellow"];
    }
    Super.prototype.sex = "男";
    Super.prototype.say = function() {
      console.log(" Oh,My God! ");
    };
    

    构造继承

    原理

    通过使用 call、apply 方法可以在新创建的对象上执行构造函数,用父类的构造函数来增加子类的实例

    实现

    function Sub() {
      Super.call(this);
      this.type = "sub";
    }
    
    var s = new Sub();
    
    console.log(s.colors); //[ 'red', 'blue', 'yellow' ]
    s.say(); //报错 sub.say is not a function
    

    优缺点

    • 优点:简单明了,直接继承超类构造函数的属性和方法
    • 缺点:无法继承原型链上的属性和方法

    原型链式继承(借用原型链实现继承)

    实现

    function Sub() {
      this.type = "sub";
    }
    Sub.prototype = new Super();
    var s1 = new Sub();
    var s2 = new Sub();
    sub1.colors.push("black");
    console.log(s1.colors); //[ 'red', 'blue', 'yellow', 'black' ]
    console.log(s2.colors); //[ 'red', 'blue', 'yellow', 'black' ]
    sub1.say();
    

    我们实例化了两个 Sub,在实例 s1 中为父类的 colors 属性 push 了一个颜色,但是 s2 也被跟着改变了。造成这种现象的原因就是原型链上中的原型对象它俩是共用的。这不是我们想要的,s1 和 s2 这个两个对象应该是隔离的,

    组合继承

    这里所谓的组合是指组合借用构造函数和原型链继承两种方式。

    function Sub() {
      Super.call(this);
      this.type = "sub";
    }
    Sub.prototype = new Super();
    var s1 = new Sub();
    var s2 = new Sub();
    s1.colors.push("black");
    console.log(s1.colors); //[ 'red', 'blue', 'yellow', 'black' ]
    console.log(s2.colors); //[ 'red', 'blue', 'yellow' ]
    

    可以看到,s2和s1两个实例对象已经被隔离了,但这种方式仍有缺点。父类的构造函数被执行了两次,第一次是Sub.prototype = new Super(),第二次是在实例化的时候,这是没有必要的。那我们就继续优化吧!!

    组合式继承优化1

    function Sub(){
        Super.call(this)
        this.type = "sub";
    }
    Sub.prototype=Super.prototype
    var s1=new Sub()
    var s2=new Sub()
    

    但是请看以下代码

    console.log(s1.constructor.name);//Super
    

    我们还可以用.constructor来观察对象是不是某个类的实例:从这里可以看到,s1的构造函数居然是父类Super,而不是子类sub,这显然不是我们想要的。

    组合式继承优化2

    function Sub(){
        Super.call(this)
        this.type = "sub";
    }
    Sub.prototype=Super.prototype
    Sub.constructor=Sub
    var s1=new Sub()
    var s2=new Sub()
    console.log(s1 instanceof Sub);//true
    console.log(s1 instanceof Super);//true
    console.log(s1.constructor.name);//Super
    

    perfect!!

    开题解答

    回到开头的问题中来,

    function A(){}
    A.prototype.consoleA=function(){
        console.log("a")
    }
    function B(){
        A.call(this)
    }
    B.prototype.consoleB=function(){
        console.log("b")
    }
    Object.assign(B.prototype,A.prototype)
    function C(){
        B.call(this)
    }
    C.prototype.consoleC=function(){
        console.log("c")
    }
    Object.assign(C.prototype,B.prototype)
    
    

    参考资料

    前端面试必备之JS继承方式总结
    大前端之路----JS继承的六种方式

  • 相关阅读:
    教你一个vue小技巧,一般人我不说的
    分享一个好用的函数吧,将js中的对象转成url参数
    Vue源码探究-源码文件组织
    后端分布式系列:分布式存储-HDFS DataNode 设计实现解析
    Android Animation动画详解(二): 组合动画特效
    后端分布式系列:分布式存储-HDFS NameNode 设计实现解析
    Android开源框架ViewPageIndicator和ViewPager实现Tab导航
    解决某些手机RadioGroup中的RadioButton不居中(右移)问题
    Android Animation动画详解(一): 补间动画
    后端分布式系列:分布式存储-HDFS 架构解析
  • 原文地址:https://www.cnblogs.com/jerrypig/p/9896811.html
Copyright © 2011-2022 走看看