javascript 中的原型 ,原型链 ,继承

在js 中讲到 面向对象,就离不开原型  原型链  继承   等等概念;那么这些具体是什么,我们一起来深入理解。

function Dog(name){
   this.name= name ;
   this.barking = '汪汪汪';
}
var dog1 = new Dog('大狗');
var dog2 = new Dog ('二狗');

console.log(dog1);//{name:'大狗',barking:'汪汪汪'}
console.log(dog2); //{name:'二狗',barking:'汪汪汪'}
dog1.barking='汪汪';

console.log(dog1);//{name:'大狗',barking:'汪汪'}
console.log(dog2); //{name:'二狗',barking:'汪汪汪'}

从上面的代码 我们先声明了一个Dog 的 构造函数, 对Dog 使用new 关键字生成 对应的实例对象,从上面修改其中一个实例对象的属性,另一个不受影响。其实,每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费
javascript 的设计者 希望可以共享需要的方法和属性 ,此时 ,现在去掉实例中的 Barking 属性, 添加 prototype .

function Dog(name){
   this.name= name ;
}
Dog.prototype = { Barking : '汪汪汪,汪汪' }
 console.log(dog1.Barking) //  '汪汪汪,汪汪' 
 console.log(dog2.Barking) // '汪汪汪,汪汪'

 现在, Barking属性放到原型对象中, 只需要修改原型中的Barking ,  两个实例都能共享发生变化。
2. 原型链 :讲到原型 ,离不开原型链 , 讲到原型链离不开 _proto_  ;  

原型链是在Object.create() 或 DOG.prototype 创建原型对象时,生成的  _proto_ 指针来实现的 。
 如上例  实例对象dog1 的   _proto_ 指针, 指向了构造函数的原型对象Dog.prototype,原型对象上的_proto_ 指Object.prototype  ;
以上例 说明 当访问dog1上的Barking 属性 , 会先在dog1 上自有属性上找, 如果没有找到会通过_proto_指针 在 Dog.prototype ,找到了return 对应的值, 没有找到会继续沿着_proto_ 在 ,Object.prototype  ,终点为null 。

以上可以描述为 xxx.__proto__.__proto__.__proto__  ,通过_proto_ 指针 形成一个访问属性 或者方法的链 即为原型链;

总结一下原型链作用:对象属性的访问修改和删除。

  1. 访问。优先在对象本身查找,没有则顺着原型链向上查找
  2. 修改。只能修改跟删除自身属性,不会影响到原型链上的其他对象。

为了更好理解 原型可以参考下图


3.继承 

es5 以及更早的版本是通过 上方原型的方式进行继承, 组合继承 :

function Father (name){
  this.name= name;
}
 Father.prototype.say=function (){
   console.log('my name is ' + this.name);
}
function Child  (name){
    Father.call(this,name);  //  继承 构造函数Father的属性
}
Child.prototype = new Father() ;  Child 原型中的_proto_指针会指向 Father.prototype, 继承 构造函数Father 的原型;
或者 :
 //Child.prototype= Object.create(Father.prototype,{
//constructor:{
 //     value:Child,
 //     enumerable:false,
  //    writable:true,
  //    configurable:true,
 // }
 // })

var children1 = new Child('Tom'); 
children1.say(); // my name is Tom  
寄生组合继承

function ParentFn(name,age){
      this.color='red'
      this.name=name;

}
 ParentFn.prototype.sayName= function(){
      console.log(this.name);
   }

function ChildFn(parentName,childName){
      ParentFn.call(this, parentName);
      this.childName = childName;
     
}

  ChildFn.prototype=Object.create(ParentFn.protoType);

   ChildFn.prototype.constructor= ChildFn;



最后children1  访问say方法 , 先在自身找, 再通过 _proto_  在Child.prototype 找, 再通过 Child.prototype的_proto_在Father  的原型上找到say 方法 调用。
注释部分的  的原型继承(寄生式继承) : 其核心 把父类的 原型方法 赋值给了子类的原型, 并且把构造函数设置为子类, 这样避免,解决了父类构造函数中无用的属性,还可以正确找到子类的构造函数。

es6 中采用  class, extends 关键字实现继承, 使用起来非常方便,

class Parent {
   constructor(name){
      this.name=name;
         }
  getName(){
     console.log(this.name)
     }
 };
class Child extends Parent {
   constructor(name){
     super(name);
    }
};

var children1 = new  Child('Tom');
children1.getName(); // Tom

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值