JS 之 继承

ES6之前:继承主要分为 原型链继承、构造函数继承、组合继承、寄生组合继承(最终继承方式)

ES6之后:class继承

目录

1.原型链继承

2.构造函数继承(借用构造函数)

3.组合继承

4.寄生组合继承(最终方案)

ES6之后:使用class、extends实现继承


1.原型链继承

原型链继承通过修改子类的原型为父类的实例,从而实现子类可以访问到父类构造函数以及原型上的属性或者方法

优点:好理解,逻辑清晰

缺点:不好传参数,无法定制化对象,若父类有引用类型,如数组,数据可能公用

function Person() {
  this.name = 'coder'
}
Person.prototype.eat = function () {
  console.log(this.name + ' eating')
}

function Student(name) {
  this.name = name
}

//因为  new Peoson(),这个对象的__proto__指向Person.prototype  
Student.prototype = new Person()

// 错误写法
// 这样写的话,Student类中的私有方法也会加到Person.prototype中,对于面向对象而言,是错误的
Student.prototype = Person.prototype


let s = new Student('str')
s.age = 17

console.log(s) // { name: 'str', age: 17 }



2.构造函数继承(借用构造函数)

通过call,this来实现继承,在子类中调用父类的构造函数

优点:可以进行传参,定制对象了

缺点:属性和方法都写在一起,浪费空间资源,因为方法都是一样的,不应该每次重新创建

function Person(name,age) {
  this.name = name
  this.age = age
  this.eat = function () {
    console.log(this.name + ' eating')
  }
}


function Student(name,age,sno) {
  // 用call调用父类构造函数,实现代码复用
  Person.call(this,name,age)
  this.sno = sno
}


let s = new Student('str', 17)

console.log(s) // { name: 'str', age: 17, eat: [Function (anonymous)] }


3.组合继承

原型链继承、构造函数继承结合在一起,就是组合继承

优点:解决构造函数继承中,每次创建对象方法也跟着创建的问题

缺点:1.父类至少被调用了两次,一次是call调用,一次是改变子类prototype指向时调用

           2.子类的prototype上也会存在属性,值都为undefined,这其实时不必要的

function Person(name,age) {
  this.name = name
  this.age = age
}
Person.prototype.eat = function () {
  console.log(this.name + ' eating')
}

function Student(name,age,sno) {
  // 用call调用父类构造函数,实现代码复用
  Person.call(this,name,age)
  this.sno = sno
}

Student.prototype = new Person()
// 因为修改了Student.prototype指向,导致没有constructor属性,会通过原型链找到父类,所以打印出来的类型是父类的
// 手动增加constructor属性指回自己
Student.prototype.constructor = Student



4.寄生组合继承(最终方案)

优点:最终方案,完美

缺点:应该没有

// 让子类继承父类
function inter(childObj, superObj) {
  childObj.prototype = createObj(superObj.prototype)
  childObj.prototype.constructor = childObj
}
// 拐一个弯实现
function createObj(o) {
  function foo() {}
  foo.prototype = o
  return new foo()
}

//------------------------------------

function Person(name, age) {
  this.name = name
  this.age = age
}
Person.prototype.eat = function () {
  console.log(this.name + ' eating')
}

function Student(name, age, sno) {
  Person.call(this, name, age)
  this.sno = sno
}

// 1.可以这么继承    可能有兼容问题
// Student.prototype = Object.create(Person.prototype)
//Student.prototype.constructor = Student
// 2.手动实现继承
inter(Student, Person)

Student.prototype.stuny = function () {
  console.log(this.name + ' study')
}

let s = new Student('小明', 15, 11223)
console.log(s)
s.eat()
s.stuny()

ES6之后:使用class、extends实现继承

class Person {
  // 赋值写在构造器中
  constructor(name, age) {
    this.name = name
    this.age = age
  }

  running() {
    console.log(this.name + ' running');
  }
}

class Student extends Person {
  constructor(name, age, sno) {
    // 若使用了构造器接受参数,super必须位于第一行
    super(name, age)
    this.sno = sno
  }

  studing() {
    console.log(this.name + ' studying');
  }
}

let stu = new Student('小明', 14, 00001)

stu.running() //小明 running
stu.studing() //小明 studying
console.log(stu); //Student { name: '小明', age: 14, sno: 1 }

猜你喜欢

转载自blog.csdn.net/a15297701931/article/details/120640860