JS继承方法和实现原理

1.js中继承实现的方法

实现继承首先需要一个父类,在js中实际上是没有类的概念,在es6中class虽然很像类,但实际上只是es5上语法糖而已
js中实现继承的方法共有七种,分别是:
1)原型链继承
2)借用构造函数继承
3)实例继承(原型式继承)
4)拷贝继承
5)组合式继承
6)寄生组合式继承
7)es6继承

★原型链继承:

把父类的实例作为子类的原型(利用原型让一个引用类型继承另一个引用类型的属性和方法)
优点:简单易于实现,父类新增的实例与属性子类都能访问到
缺点:
♢ 可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new父类构造函数的后面
♢无法实现多继承
♢2在创建子类型的实例时,没有办法在不影响所有对象实例的情况下给超类型的构造函数中传递参数。

function person(){}
person.protype = new people()
person.protype.name = 'qianqian'
let obj = new person

★借用构造函数继承

复制父类的实例属性给子类(在子类型的构造函数中调用超类型构造函数。)
优点:
♢解决了子类构造函数向父类传递参数的问题
♢可以实现多继承(call或apply多个父类)
♢解决了原型中包含实例引用类型值被所有实例共享的问题
缺点:
♢方法都在构造函数中定义,无法复用,
♢不能继承原型属性、方法,只能继承父类的实例属性和方法

function person(age){
people.call(this)
this.age = age || '20'
}
let obj = new person

★实例继承(原型式继承)

借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
优点:
♢不限制调用方式
♢简单,易实现
缺点:
♢同原型链实现继承一样,包含应用类型的值会被所有的实例共享

function persoon(name){
let people = new peo()
people.name = name || "qianiqan"
return people

★拷贝继承

特点:支持多继承
缺点:
效率较低,内存占用高(因为要拷贝父类的属性)
无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

function Cat(name){
  var animal = new Animal();
  for(var p in animal){
    Cat.prototype[p] = animal[p];
  }
  Cat.prototype.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

★组合式继承

调用父类构造函数。继承父类属性,通过将父类实例作为子类原型,实现函数复用
优点:
♢函数可以复用
♢不存在引用属性问题
♢可以继承属性和方法,并且可以继承原型的属性和方法
缺点:
♢由于调用了两次父类,所以产生了两份实例

function People(name,age){
  this.name = name || 'wangxiao'
  this.age = age || 27
}
People.prototype.eat = function(){
  return this.name + this.age + 'eat sleep'
}

function Woman(name,age){
  People.call(this,name,age)
}
Woman.prototype = new People();
Woman.prototype.constructor = Woman;
let wonmanObj = new Woman(ren,27);
wonmanObj.eat(); 

★寄生组合继承

通过寄生的方式来修复组合式继承的不足,完美的继承
优点:
♢只调用了一次超类构造函数,效率高,避免在超类型的prototype上面创建不必要的,多余的属性,于此同时,原型链还能保持不变

//父类
function people(name,age){
this.name = name || 'qianqian'
this.age = age || 18
}
//方法
people.protype.eat = function(){
return this.name + this.age + 'eat sleep'
}
//子类
function person(name ,age){
//继承父类属性
people.call (this.name ,age)
}
//创建父类方法
(function(){
let super = function(){}
super.prototype = people.peotype
person.peotypr = new super()
})()
person.protype.constructor = person
let obj = new person()

★ES6继承

优点:代码少,容易理解

//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
class People{
  constructor(name='wang',age='27'){
    this.name = name;
    this.age = age;
  }
  eat(){
    console.log(`${this.name} ${this.age} eat food`)
  }
}
//继承父类
class Woman extends People{ 
   constructor(name = 'ren',age = '27'){ 
     //继承父类属性
     super(name, age); 
   } 
    eat(){ 
     //继承父类方法
      super.eat() 
    } 
} 
let wonmanObj=new Woman('xiaoxiami'); 
wonmanObj.eat();


ES5继承和ES6继承的区别:

es5继承首先是在子类中创建自己的this指向,最后将方法添加到this中
Child.prototype=new Parent() || Parent.apply(this) || Parent.call(this)
es6继承是使用关键字先创建父类的实例对象this,最后在子类class中修改this

  • 9
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值