美文网首页
(4)JavaScript继承模式二

(4)JavaScript继承模式二

作者: jaimor | 来源:发表于2019-04-22 12:57 被阅读0次

    上一篇文章说了继承模式,其实上一章节的继承模式是有一点瑕疵的,这个瑕疵并不是由模式引起的,而是由JavaScript自身原型链引起的。比如我们来改一改上一章节(请先看上一篇文章,这里不做阐述)中的代码:

    //父类
    function Supper(msg) {
      this.msg = msg;
      this.supperVal = ["supper", "val"];      //只将此处修改为引用类型,其他不做修改
    }
    Supper.prototype.say = function () {
      console.log(this.msg);
    }
    Supper.prototype.getSupperVal = function () {
      return this.supperVal;
    }
    new Supper("i am supper").say();    // i am supper
    
    //子类
    function Sub(msg) {
      this.name = "sub";            //对父类的拓展,父类没有,而子类有的属性
      this.msg = msg;               //覆盖、修改父类的属性
    }
    Sub.prototype = new Supper("supper class");  //这里只是修改了父类的msg
    //拓展了一个新的方法、功能
    Sub.prototype.who = function () {
        console.log(this.name);
    }
    var sub = new Sub("i am sub");    //子类msg为 i am sub
    sub.who();      // sub,这里是对父类的属性、方法进行的拓展
    sub.say();      // i am sub,这里是对父类的属性进行覆盖
    sub.getSupperVal();    //supperVal,这里是对父类的属性进行继承
    
    sub实例对象

    然后我们来创建一个sub2实例。

    var sub2 = new Sub("i am sub2");
    
    sub2实例对象

    这样也没有问题。拥有了自己的属性name,也覆盖了父类属性msg,也继承了父类属性supperVal和方法。看似都很完美,接下来注意了。我们要来修改下sub2中冲父类继承过来的属性supperVal。

    sub2.supperVal.push("sub2 modify");    //愿意只是向修改sub2中的supperVal的值,但结果却不是这样!!!
    
    修改后的结果

    可以看到的是,我仅仅只是使用sub2修改自己的supperVal的值,但是影响到了其他实例的属性,这在开发中可要造成严重的BUG,值得注意!!!当然,如果supperVal是非引用类型,是不会有这样的问题的,而为什么使用引用类型的时候,会出现这样的问题,这就是JavaScript自身原型链里的知识了,这里不做阐述。我们这里主要是要完善这种继承模式中可能会出现类似的问题。
    出现这种问题的原因就是,子类继承的过来的属性在原型链上。所以如果我们将父类继承过来的属性嵌入到子类中,而不是原型链中,岂不是就可以了。

    // 子类做一点小修改,规避这样的问题
    //子类
    function Sub(msg) {
      Supper.call(this, msg);      //这里就将父类中的属性全部在子类中执行一边(相当于拷贝了一份在子类中)
      this.name = "sub";            //对父类的拓展,父类没有,而子类有的属性
      //this.msg = msg;             //此处就不需要了
    }
    Sub.prototype = new Supper("supper class");  //这里的目的就只是拷贝父类原型链中的方法(因为属性已经通过Supper.call(this, msg)拷贝了)
    

    完整代码如下:

    //父类
    function Supper(msg) {
      this.msg = msg;
      this.supperVal = ["supper", "val"];      //只将此处修改为引用类型,其他不做修改
    }
    Supper.prototype.say = function () {
      console.log(this.msg);
    }
    Supper.prototype.getSupperVal = function () {
      return this.supperVal;
    }
    new Supper("i am supper").say();    // i am supper
    
    //子类
    function Sub(msg) {
      Supper.call(this, msg);      //这里就将父类中的属性全部在子类中执行一边(相当于拷贝了一份在子类中)
      this.name = "sub";            //对父类的拓展,父类没有,而子类有的属性
      //this.msg = msg;             //此处就不需要了
    }
    Sub.prototype = new Supper("supper class");  //这里只是修改了父类的msg
    //拓展了一个新的方法、功能
    Sub.prototype.who = function () {
        console.log(this.name);
    }
    var sub = new Sub("i am sub");    //子类msg为 i am sub
    var sub2 = new Sub("i am sub2");
    sub2.supperVal.push("sub2 modify");
    
    结果

    相关文章

      网友评论

          本文标题:(4)JavaScript继承模式二

          本文链接:https://www.haomeiwen.com/subject/fdtzwqtx.html