javaScript中如何理解继承

492 阅读4分钟

1.什么是继承?

我理解的继承就是子类继承父类的行为和特征,使得子类对象具有父类的属性和方法。

2.如何实现继承?

  • 1.通过原型链的方式实现继承
  	function Person(name) {
            this.name = name
            this.colors = ['red', 'blue']
        }
        Person.perototype.sayhi = function () {
        	console.log('hi')
        }
    	function Man (age) {
            this.age = age
            this.gender = '男'
    	}
       Man.prototype = new Person()
       //此时Man的实例对象的原型链是 Man的实例对象 => Man.prototype(Person的实例对象)
       //=> Person.prototype => Object.prototype
       //根据原型链可以实现Man使用Person的方法和属性
       const p1 = new Man(20)
       p1.colors.push('green')
       const p2 = new Man(21)
       console.log(p1.colors)
       console.log(p2.colors)
       p.sayhi()
  • 通过原型链的方式的优点和缺点: 优点: 通过原型链的方式可以实现父类方法和属性的继承,并且可以通过instanceof来确定继承的父类 缺点: 不能通过向父类进行传参、 如果父类属性中有引用值(如数组),会在子类的所有实例对象中共享,因此其中一个改变父类中的引用值,那么会导致在所有的子类实例对象中都改变
  • 2.通过构造函数的方式实现继承
      function  Animal(name) {
          this.name = name
          this.colors = ['red', 'blue']
          this.sayhi = function () {
          	console.log('hi')
          }
      }
      function Dog(name,age, gender) {
          Animal.call(this, name)
          this.age = age
          this.gender =gender
      }
      const dog = new Dog('小黑', 3, '男')
      console.log(dog.name)
      dog.sayhi() //通过构造函数的方式不会改变原型链, Dog的原型链还是Dog的实例对象 =>
      // Dog.prototype => Object.prototype 因此子类不能调用父类构造函数原型上的方法
  • 通过构造函数的方式的优点和缺点: 优点: 通过构造函数的方式实现继承,可以向父类进行传参。构造函数的方式父类属性中有引用值,不会造成会在所有的实例对象中共享。 缺点: 需要两次调用父类构造函数,效率浪费。必须在父类构造函数中定义方法,因此函数不能重用。子类不能调用父类构造函数原型上的方法。
  • 3.通过组合继承的方式实现继承(通过构造函数实现属性的继承,通过原型链的方式实现继承原型上的属性和方法)
      function Person (name) {
        this.name = name
        this.colors = ['red', 'blue']
      }
      Person.prototype.sayhi = function (){
      	console.log('hi')
      }
      function Man (name, age, gender) {
      	Person.call(this, name)
        this.age = age
        this.gender = gender
      }
      Man.prototype = new Person
      const p1 = new Man('张三', 20, '男')
      p1.colors.push('green')
      const p2 = new Man('李四', 18, '男')
      console.log(p1.colors)
      console.log(p2.colors)
      //此时原型链是 Man的实例对象 => Man.prototype(Person的实例对象) =>Person.prototype => Object.prototype

通过组合继承的方式的优点和缺点: 优点: 解决了原型链继承和原型链继承的缺点 缺点: 仍然是会调用两次父类构造函数

  • 4.通过原型式继承的方式实现继承
    function create(o) {
      function F (){}
      F.prototype = o
      return new F()
    }
    //此方法的作用就是传递一个对象进去,返回一个临时类型的实例 本质上:create对传入的对象进行了一次浅复制
    const object = {
      name = '张三'
      colors = ['red', 'blue']
    }
    const p = create(object)
    console.log(p)	
   	//此时的原型链为:p => F.prototype => Object.prototype

通过原型式继承的方式的优点和缺点: 优点: 不需要单独创建构造函数 缺点: 和原型链继承的方式一样,所有的实例对象仍然会共享信息

  • 5.通过寄生式继承
    	function create(o) {
          function F (){}
          F.prototype = o
          return new F()
      }
  	function createAnother(object) {
          const clone = create(object)// 通过调用函数创建一个对象
          clone.sayhi = function () {//增强这个对象
          	console.log('hi')
        }
        return clone
    }
    const Person = {
    	name: '张三',
        colors: ['blue', 'red']
    }
    const anotherPerson = createAnother(Person)
    anotherPerson.sayhi()
    //此时的原型链为: anotherPerson => F.prototype => Object.prototype

通过寄生式继承的优点和缺点: 优点: 可以自己定义方法 缺点: 引用值仍然会在所有的实例对象中共享信息,而且给对象添加函数会导致函数难以重用。

  • 6.通过寄生组合式继承
      function Person(name) {
      	this.name = name
        this.colors = ['red', 'blue']
      }
      Person.prototype.sayhi = function () {
      	console.log('hi')
      }
      function Man (name, age, gender) {
      	Person.call(this, name)
      	this.age = age
        this.gender = gender
      }
      function inheritPrototype (Man, Person) {
      	const o = create(Person.prototype) //创建一个对象
        o.constructor = Man
        Man.prototype = o
      }
      inheritPrototype(Man, Person)
      //此时原型链是: Man的实例对象 => Man.prototype => Person.prototype => Object.prototype

通过寄生式组合继承是引用类型继承的最好方式

3.ES6中实现继承的方式

使用extends关键字,就可以继承任何拥有[[construct]]和原型的对象
派生类的方法可以通过super关键字引用它们的原型。
关于ES6中的类以及ES6中继承的具体内容会在后面的文章中发布