继承的六种方法

一 、原型链继承

function Person() {
  this.name = 'Person'
}
Person.prototype.eating = function () {
  console.log(this.name + 'eating~')
}
// 子类:特有属性和方法
function Student() {
  this.sno = 111
}
const p = new Person()
Student.prototype = p
Student.prototype.studying = function () {
  console.log(this.name + ' studying~')
}
const stu = new Student()
console.log(stu.name) // Person
stu.eating() // Person eating~
stu.studying() // Person studying~

特点: 1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新 实例不会继承父类实例的属性!

缺点: 1、新实例无法向父类构造函数传参。

2、继承单一。

3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属 性,另一个实例的原 型属性也会被修改!)

二、借用构造函数继承

function Person(name, age, friends) {
  this.name = name
  this.age = age
  this.friends = friends
}
Person.prototype.eating = function () {
  console.log(this.name + ' eating~')
}
function Student(name, age, friends, sno) {
  Person.call(this, name, age, friends)
  this.sno = 111
}
const p = new Person()
Student.prototype = p
Student.prototype.studying = function () {
  console.log(this.name + ' studying~')
}
const stu = new Student('Student', 18, ['kobe'], 111)
console.log(stu.name)  // Student
stu.eating() // Student studying~
stu.studying()//Student eating~

重点:.call()和.apply() 将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复 制))

特点: 1、只继承了父类构造函数的属性,没有继承父类原型的属性。

2、解决了原型链继承缺点 1、2、3。

3、可以继承多个构造函数属性(call 多个)。

4、在子实例中可向父实例传参。

缺点: 1、只能继承父类构造函数的属性。

2、无法实现构造函数的复用。(每次用每次都要重新调用)

3、每个新实例都有父类构造函数的副本,臃肿。

三、组合继承(组合原型链继承和借用构造函数继承)(常用)

function Person(name, age, friends) {
  this.name = name
  this.age = age
  this.friends = friends
}
Person.prototype.eating = function () {
  console.log(this.name + ' eating~')
}
//子类
function Student(name, age, friends, sno) {
  Person.call(this, name, age, friends)
  this.sno = 111
}
// 直接将父类的原型赋值给子类, 作为子类的原型
// 直接将 Person.prototype 赋值给 Student.prototype 会导致 Student.prototype 和 Person.prototype 指向同一个对象,因此对 Student.prototype 的修改也会影响到 Person.prototype,因此使用`Object.create` 来创建一个新的对象,并将其赋值给 `Student.prototype`,以保持继承关系的正确性
Student.prototype = Object.create(Person.prototype)
Student.prototype.studying = function () {
  console.log(this.name + ' studying~')
}
const stu = new Student('student', 18, ['friend'], 111)
console.log(stu) // Person { name: 'student', age: 18, friends: [ 'friend' ], sno: 111 }
stu.eating() // student eating~

重点: 结合了两种模式的优点,传参和复用

特点: 1、可以继承父类原型上的属性,可以传参,可复用。

2、每个新实例引入的构造函数属性是私有的。

缺点: 调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函 数。

四、原型式继承

let obj = {
  name: 'why',
  age: 18
}
let info = Object.create(obj)
console.log(info)
console.log(info.__proto__)

重点: 用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的 实例或对象。object.create()就是这个原理。

特点: 类似于复制一个对象,用函数来包装。

缺点: 1、所有实例都会继承原型上的属性。 2、无法实现复用。(新实例属性都是后面添加的)

五、寄生式继承

let personObj = {
  running: function () {
    console.log('running')
  }
}
function createStudent(name) {
  let stu = Object.create(personObj)
  stu.name = name
  stu.studying = function () {
    console.log('studying~')
  }
  return stu
}

let stuObj = createStudent('why')
let stuObj1 = createStudent('kobe')
let stuObj2 = createStudent('james')

重点: 就是给原型式继承外面套了个壳子。

优点: 没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成 了创建的新对象。

缺点: 没用到原型,无法复用。

六、寄生组合式继承

 function Parent() {
  this.name = "parent";
   this.fun = () => {
     console.log("fun");
   };
   this.friends = [1, 2, 3];
 }
 Parent.prototype.me = () => {
   console.log("11");
 };
 function Child() {
   Parent.call(this);
   this.sex = 1;
 }
 function clone(parent, child) {
   // 这里改用Object.create可以减少组合继承中执行父类构造函数的次数
   child.prototype = Object.create(parent.prototype);
   child.prototype.constructor = child;
 }

 //   Child.prototype = new Parent();
 //   Child.prototype.constructor = Child;//封装这两句话
 clone(Parent, Child);
 let child1 = new Child();
 let child2 = new Child();
 console.log(
   child1.name === child2.name,
   child1.fun === child2.fun,
   child1.friends === child2.friends
 );//true false false
 child1.name = "xiaogui";
 child1.fun.a = 1;
 child1.friends.push(4);
 console.log(child1.name, child2.name);//xiaogui parent
 console.log(child1.fun.a, child2.fun.a);// 1 undefined
 console.log(child1.friends, child2.friends);//[1,2,3,4] [1,2,3]
 child2.me();//11

这个方法比较成熟 前面继承方式弊端基本解决 只调用一次父类构造函数 Child可以向Parent传参 父类方法可以复用 父类的引用属性不会被共享 ES6中的类继承extends也是使用寄生组合继承原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值