关于原型链与继承

1.原型、原型链、继承的概念

(1)每个构造函数都有一个原型对象,原型对象都包含指向构造函数的指针,而实例都包含一个指向原型对象的内部指针(__proto__);

(2)一个对象会指向一个原型,原型对象会有自己的原型,以此类推,构成原型链。

(3)实例使用方法和属性时,会先从构造函数内部找,找不到再去原型对象上找,还找不到就去原型对象的原型上找,直到(原型对象的原型为null)
Object.prototype.__proto__===null,停止查找.

(4)继承是指能够访问另外一个对象中的方法和属性。

2.实现继承的几种方式:(主要是原型链继承)

(1)原型链继承

//原型链继承
function Person(name,age){
  this.name=name;
  this.age=age;
  this.desc=function(){
    console.log("this is a person");
  }
}
Person.prototype.common=function(){
  console.log("恭喜您出生了");
}
function Teacher(name,age,skill){
  this.name=name;
  this.age=age;
  this.skill=function(){
    console.oog("传授知识");
  }
}
//实现继承的关键

Teacher.prototype=new Person();

总结:子类继承的实现:将父类的实例赋值给子类的原型。
缺点是:(1)子类原型的构造函数指向的是父类构造函数,Person.prototype.constructor === Teacher.prototype.constructor.
(2)无法给父类构造函数传参数
(3)所有子类的实例共享父类构造函数的属性方法。

(2)构造函数继承

function Person(name,age){
  this.name=name;
  this.age=age;
  this.desc=function(){
    console.log("this is a person");
  }
}
Person.prototype.common=function(){
  console.log("恭喜您出生了");
}
function Teacher(name,age,skill){
  Person.call(this,name,age);
}

总结:该类继承方式,是在子类的定义中改变父类的this指向(即父类的执行环境),缺点是无法访问父类原型对象上的方法。

(3)组合式继承

function Person(name,age){
  this.name=name;
  this.age=age;
  this.desc=function(){
    console.log("this is a person");
  }
}
Person.prototype.common=function(){
  console.log("恭喜您出生了");
}
function Teacher(name,age,skill){
  Person.call(this);// 第一次调用父类
}
Teacher.prototype=new Person();//第二次调用父类

总结:该继承方式结合了原型链和构造函数的继承方式;
缺点:
(1)会调用两遍父类构造函数
(2)会出现 Teacher.prototype.constructor === Person.prototype.constructor

(4)寄生式继承

let obj={
  name:1,
  age:2
};
function createObj(obj){
   function F(){
   };
   F.prototype=obj;
   return new F();
 }
function createPerson(obj){
  let clone=createObj(obj);
  return clone;
}
let p1=createPerson(obj);

总结:模式与工厂模式类似,创建一个仅用于封装继承过程的函数。

(5)寄生组合式继承

function initPrototype(fatherType,childType){
  let prototypeF=createOb(fatherType.protoType);//创建对象
  prototypeF.constructor=childType;//增强对象
  childType.prototype=prototypeF;//指定对象
};
function createObj(obj){
  function F(){
  };
  F.prototype=obj;
  return new F();
}
function Father(name){
  this.name=name;
};
Father.prototype.skill=function(){
  console.log("father's skill");
};
function Child(){
   Father.call(this, ...arguments);
};
initPrototype(Father,Child);
Child.prototype.change=function(){
  console.log("Child changing");
}

总结:通过借用构造函数来继承属性,通过原型链的混成形式来继承的方法。对于父类的原型继承,相当于是将父类的原型对象的副本赋值给子类的原型,这样避免了在子类原型上面添加其他多余的属性,子类的原型和原型指向的构造函数也不再混乱了。

(6)ES6中的class相关的继承

class Animal{
  constructor(name,type){
      this.name="everything";
      this.type=type;
      this.skill1=function(){
          console.log("animal");
      }
  }
  change(){
      console.log("changeing")
  }
};
class Bird extends Animal{
    
  constructor(name,type){
      super(name,type);
     this.skill=function(){
         console.log("flying");
     }
  }
};
let b1=new Bird();
b1.change();

(7)通过Object.create实现继承
作用: 以一个现有对象作为原型,创建一个新对象

function Father () {
}
Father.prototype.run = function () {
  console.log('is running')
}
function Child () {
  Father.call(this) // 调用父类构造函数。
}
Child.prototype = Object.create(Father.prototype, {
  constructor: {
  value: Child,
  enumerable: false,
    writable: true,
    configurable: true,
  }
})

备注:参考自JAVASCRIPT高级程序设计

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值