js中的继承详解

版权声明:本文为博主原创文章,评论区告知一声,大家随意转载! https://blog.csdn.net/MessageBox_/article/details/82755508

js中的继承

假设我们有一个Animal类,我们想构造Cat类,Cat类可以继承Animal类的属性和方法。以这个场景为列,我来讲一讲我所理解的js的继承。

  1. 构造继承
function Animal(name){
  this.name = name;
  this.age = 15;
}

function Cat(name){
  Animal.call(this, name);
  this.catName = 'cat';
}

let o1 = new Cat('test1');
console.log(o1);
//Cat {name: "test1", age: 15, catName: "cat"}

这就是构造继承,在子类的构造函数中,调用父类的构造函数,这样父类构造函数中的属性就出现在了子类的构造函数中。
缺点:子类无法继承父类原型上的方法。

  Animal.prototype.say = function(){
     console.log(this.name)
  }
  o1.say;//undefined
  1. 原型继承
  function Cat2(name){
    this.catName = name;
  }
  Cat2.prototype = new Animal();
  let o2 = new Cat2('test2');
  console.log(o2);
  // Cat2 {catName: "test2"}
  o2.name;//undefined
  o2.age;//15
  o2.say;
  //ƒ (){
  //  console.log(this.name)
  //}

这种方法的缺点是无法进行父类传参初始化属性的继承,而且继承的父类的属性是所有子类共享的new Animal()这个对象实例上的属性,这就会导致如果更改了该对象实例的属性,那么这个影响就是所有子类实例共享的。
我们对父类做出如下更改

  function Animal(name){
    this.name = name;
    this.age = 15;
    this.friend = [1,2,3];
  }

  function Cat21(name){
    this.catName = name;
  }

  Cat21.prototype = new Animal();
  
  let o3 = new Cat21('o3');
  let o4 = new Cat21('o4');
  console.log('o3.age',o3.age);
  console.log('o4.age',o4.age);
  console.log('o3.friend',o3.friend);
  console.log('o4.friend',o4.friend);
  
  //更改数组friend
  o3.friend.push(4);
  console.log('o3.friend',o3.friend);
  console.log('o4.friend',o4.friend);
  
  //更改属性age
  o3.age = 19;
  console.log('o3.age', o3.age);
  console.log('o4.age', o4.age);

输出如下

    o3.age 15
    o4.age 15
    o3.friend (3) [1, 2, 3]
    o4.friend (3) [1, 2, 3]
    o3.friend (4) [1, 2, 3, 4]
    o4.friend (4) [1, 2, 3, 4]
    o3.age 19
    o4.age 15

我们可以发现更改friend时,这个更改在子类实例上都发生了改变,而更改age时,只在更改的实例上发生了变化。
我们来看看o3和o4
avatar
可以发现o3上的age属性是直接在实例上的,而o3和o4的实例本身都是没有friend属性的。
这是为什么呢?
这是因为在查找对象的属性和方法时,是沿着原型链进行查找的,而你更改属性时,如果这个属性不是一个引用类型,是会直接为实例对象本身添加一个相应的属性,如果是引用类型,是会改变所引用对象指向的内容的。 而原型链上的方法,是等同于非引用类型的属性的。
因此,如果我们想要修改age,让所有实例共享修改后的结果,我们可以这么修改
o3.__proto__.age = 99;
当然,这个前提是子类实例上还没有新增age属性。

  1. 构造 + 原型继承
     function Animal(name){
       this.name = name;
       this.age = 15;
       this.friend = [1,2,3];
     }
    
     Animal.prototype.say = function(){
         console.log(this.name);
     }
     function Cat3(name){
       Animal.call(this, name);
       this.catName = 'test3';
     }
     Cat3.prototype = new Animal();
    
     let o31 = new Cat3('o31');
     let o32 = new Cat3('o32');
    
     console.log('o31', o31);
     console.log('o32', o32);
     console.log('o31.friend', o31.friend);
     console.log('o32.friend', o32.friend);
    
     o31.friend.push(4);
     console.log('o31.friend', o31.friend);
     console.log('o32.friend', o32.friend);
    
     o31.say();
    

得到的输出如下:
avatar

可以发现父类的属性和方法子类实例都可以继承,但是还是有一个问题,那就是父类的构造函数多执行了一次,而这个多余的操作是不必要的。

  1. 原型+构造+优化1
    function Cat4(name){
      Animal.call(this, name);
      this.catName = name;
    }
    
    Cat4.prototype = Object.create(Animal.prototype);
    
     let o41 = new Cat4('o41');
     let o42 = new Cat4('o42');
    
     console.log('o41', o41);
     console.log('o42', o42);
     console.log('o41.friend', o41.friend);
     console.log('o42.friend', o42.friend);
    
     o41.friend.push(4);
     console.log('o41.friend', o41.friend);
     console.log('o42.friend', o42.friend);
    
     o41.say();
    

如此,我们就少进行了一个父类构造函数的执行,但是这还是有问题的

  o41 instanceof Cat4; //true
  o41 instanceof Animal; //true
  o41.constructor;//
  //ƒ Animal(name){
  //  this.name = name;
  //  this.age = 15;
  //  this.friend = [1,2,3];
  //}

也就是无法通过instanceof来确认实例对象是由父类构造还是子类构造。

  1. 原型+构造函数+优化2
    由于instanceof的本质就是在原型链上进行constructor属性的查找 ,我们可以做如下优化
 function Cat5(name){
   Animal.call(this, name);
   this.catName = name;
 }

  Cat5.prototype = Object.create(Animal.prototype);
  Cat5.prototype.constructor = Cat5;

  let o51 = new Cat5('o51');
  o51.constructor;
  //ƒ Cat5(name){
  //Animal.call(this, name);
  //this.catName = name;
  //}

以上是个人总结的继承相关的知识点,欢迎老铁们在评论区进行补充。

猜你喜欢

转载自blog.csdn.net/MessageBox_/article/details/82755508