解决 JS 对象中继承性问题之方式二:通过构造函数继承 (call 函数) 来解决继承问题

Ⅰ、继承问题:

1、什么是继承?
答:子类去继承父类的东西,称之为继承;
如:子类继承父类的属性或方法等;

2、常见的继承方式有哪些?
答:继承方式有五种:
其一、原型链继承;
其二、构造函数继承(也称 call 继承);
其三、拷贝继承;
其四、组合继承(某一种或多种继承方式的组合);
其五、寄生式组合继承;

Ⅱ、五大继承的优缺点:

1、原型链继承的优缺点:

其一、优点:
A、实现相对简单;
B、通过子类实例可以直接访问父类原型链上和实例上的成员(即:实现了继承);

其二、缺点:
A、子类实例修改引用类型值,会影响其他子类实例(但若不是引用类型就没有问题);

2、构造函数继承 (也称为 call 继承) 的优缺点:

其一、优点:
A、实现相对简单;
B、解决了原型链继承的缺点(即:子类实例修改引用类型值,不会影响其他子类实例);
C、可以在子类实例中直接向父类构造函数传参;

其二、缺点:
A、无法继承父类原型上的成员与方法;

3、拷贝继承的优缺点:

其一、优点:
A、可以在子类中直接给父类传参;
B、通过子类实例可以直接访问父类原型链和实例的成员;

其二、缺点:
A、拷贝继承在循环过程中比较消耗内存;

4、组合继承的优缺点:

其一、优点:
A、可以在子类实例中直接向父类构造函数传参;
B、通过子类实例可以直接访问父类原型链和实例的成员;

其二、缺点:
A、执行父类函数中两次的逻辑; (即:代码性能不很好,因为有些成员或方法在父类的原型链上又重新加载了一次);

5、寄生式组合继承的优缺点:

其一、优点:
A、可以在子类实例中直接向父类构造函数传参;
B、通过子类实例可以直接访问父类原型链和实例的成员;
C、解决了组合继承的缺点(即:执行父类函数中两次的逻辑),代码的性能更优化;

缺点:
A、缺点是有的,但暂时还没了解到;

Ⅲ、构造函数继承(也称为 call 继承)的实现过程及结果展示:

1、构造函数链继承(也称为 call 继承)的实现过程的代码如下:

     // 待继承的父类构造函数,名称为:Animal;
     function Animal() {
    
    
       this.hobby = ['sleep', 'play'];   // 在父类中有一个引用类型(数组)的属性值为 'hobby';
     }


     // 父类原型对象上的成员方法; (在原型上添加方法,表示:所有父类的实例对象都可以调用 eat() 方法;)
     Animal.prototype.eat = function () {
    
    
       console.log(this.name + "is eating");
     }


     // 子类的构造函数,名称为:Cat;
     function Cat(name) {
    
    
       this.name = name; // 子类自己的私有属性;
      
       Animal.call(this); // call 方法实现继承的方式就是对函数的复用;
       					  // 通过 Cat 函数的实例来调用 'Animal.call(this)' 函数时,在调用时此时的 this 指向的就是该实例,并将 Animal() 上面的属性值添加到 Cat 函数的实例上;
       					  // 此时并不能直接调用 Animal() 函数,因为此时是 Cat 实例想要访问 Animal 身上的属性值,不改变 Animal 中 this 指向的话,此时在 Animal 中的 this 指向的是 Window,并不能达到 Cat 实例访问父类属性值的目的; 
     }


    
     var c = new Cat('maomi');  // 此时 new 出来的 c 值为:{name:'maomi',hoboy:[]};  (且是一个独立的对象与空间,不与其它实例分享);
     						    
     var c2 = new Cat('maomi2');// 此时 new 出来的 c2 值为:{name:'maomi2',hoboy:[]}  (且是一个独立的对象与空间,不与其它实例分享);

     console.log(c.hobby); // 此时的输出结果为: ['sleep', 'play'];  (即:也就通过 call 方法实现了构造函数的继承操作);
                           // 此时就实现了子类实例访问了父类属性值,即:实现了继承;

     c.hobby.push('eat');  // 该操作是:在 hoboy 数组中添加 eat 属性值;

     console.log(c2.hobby); // 此时的输出结果为:['sleep', 'play'];        
     console.log(c.hobby);  // 此时的输出结果为:['sleep', 'play', 'eat'];
                            // (该输出结果就证明了:c、c2 是相对独立的对象空间;)



// 到现在为止都是展示出来了优点:
//      A、实现相对简单(即:实现了继承); 
//      B、解决了原型链继承的缺点(即:子类实例修改引用类型值,不会影响其他子类实例);
//      C、可以在子类实例中直接向父类构造函数传参; (此时未展示,可以在拷贝继承中查看传参的问题);



     c.eat();  // 此时的输出结果为:报错;    (说明:子类实例无法继承父类原型上的成员与方法);
 

// 存在的缺点:
//       A、无法继承父类原型上的成员与方法;

2、输出结果的页面展示如下:

// 下面报错的原因:在 ‘c.eat()’ 代码语句中,子类实例无法继承父类原型上的成员与方法,因此不能访问 ‘eat()’ 方法;
在这里插入图片描述

Ⅳ、小结:

其一、哪里有不对或不合适的地方,还请大佬们多多指点和交流!

其二、如果关于 JS 对象中继承方式不详细,请参考如下JS 对象中五大继承 (原型链继承、构造函数继承(call)、拷贝继承、组合继承、寄生式组合继承) 地址文章:https://blog.csdn.net/weixin_43405300/article/details/121942780

猜你喜欢

转载自blog.csdn.net/weixin_43405300/article/details/122112614