基于原型,原型链的继承许多方法及利弊

没有大白话,有的只是简短而有道理的知识。皮一下,很开心,嘿嘿嘿嘿。

//什末是原型?

原型:一个函数是一个类也是一个对象还是一个方法,只要是函数就会有它自己的prototype属性,这个属性实质是一个指针,指向函数的原型对象,我们把构造函数的原型对象称为对象实例的原型。

函数.prototype = 实例对象.__proto__

构造函数的原型就是原型对象,每一个函数都具有 prototype属性

原型对象.constructor=函数本身

//什末是原型链?

原型链:一个函数的实例对象指向另一个函数的原型对象,那末这个实例对象就会拥有另一个函数的原型上所有的属性和方法。以此类推,就会形成一个链。有点难理解啊,嘿嘿吧。借用一个例子说明白

    A.prototype={//原型
          constructor:A,
          name:'liming',
          say:function(){
          console.log(1);
        } 
     	}
     function  A(){ 
          this.sex='hhhh'
     }    
     function B(){ }
     var b=new B();
     b.__proto__=A.prototype;
      console.log( b.say,b.name,b.sex);
结果
ƒ (){
          console.log(1);
        } 
"liming" 
undefined

由此看出实例对象b可以访问A的原型上的属性和方法。(但是拿不到构造函数A自身的属性和方法)下面介绍解决方法,这样就形成一个链,以此类推,c.__proto__=B.prototype....................

形成一堆堆的链。原型链的顶端为null。

好了,重头戏来了,本文目的就是继承,前期铺垫很多,后面就好理解,继承它有多种实现方法,下面就一一列举它们的利弊

一: 传统形式-->原型链

Grand.prototype.lastName = 'DU';
function Grand(){
}
var grand = new Grand();
Father.prototype = grand;
function Father(){
}
var father = new Father();
Son.prototype = father;
function Son(){

}
var son = new Son();
console.log(son.lastName)//DU


        缺点:过多的调用了没用的属性,son会继承Father的全部属性还会继承Grand的全部属性,并且如果在Son实例化两个对象(son1,son2)时,改变一个实例化对象(son1)的属性时另一个实例化对象(son2)也会发生改变。

二:借用构造方法

 function Person(name,age,sex){
	this.name = 'du';
	this.age = age;
        this.sex = sex;
}
function Student(name,age,sex,grade){
         Person.apply(this,arguments);//用apply这个方法前提是这个方法得是new 出来的
         //此时的this的原型还是Student.prototype的
         this.grade = grade;
	 }
         var student = new Student('liming',18,'女');
         console.log(student);
        //输出结果:
        Student {name: "du", 
                age: 18, 
                sex: "女",
                grade: undefined
            }

缺点是:借用构造方法但只能借用别人的方法不能借用别人的原型,不能继承到原型链上的属性和方法。
              

三:

Father.prototype.lastName = 'DU';
	function Father(){
	}
	function Son(age){
             this.age = age;
	}
	function inherit(Target,Origin){//传两构造函数
             Target.prototype = Origin.prototype;
	}
	inherit(Son,Father);//先继承
	var son = new Son();
	var father = new Father();
	Son.prototype.sex = 'nv';
        console.log(son.lastName,son.sex,father.lastName,father.sex)// DU nv DU nv

缺点:由此得子类继承了父类的属性但子类的私有属性也被父类拿到了,为了改进这一问题引出来下面的方法

四:完美模式

function inherit(Target,Origin){//传两构造函数
	function F(){};
	F.prototype = Origin.prototype;
	Target.prototype = new F();//接用F()链接一个桥梁
	Target.prototype.constructor = Target;//将son的指向归位
	Target.prototype.uber =  Origin.prototype;//现在Target是继承 new F()但这不是它真正继承的父类而正真继承的父类就是Origin.prototype
	}
	Father.prototype.lastName = 'DU';
	function Father(){
	}
	function Son(){
	}
	inherit(Son,Father);
	Son.prototype.sex = 'nv';
	var son = new Son() ;
	var father = new  Father();
         console.log(son.lastName,son.sex,father.lastName,father.sex);//DU nv DU undefined
         

这种方式是将父类的prototype传给一个“干净的函数”的原型,再将这个“干净的函数”的原型传给子类的原型,巧妙的用了一个函数进行过渡,这样下来子是子,父是父,间接性的形成继承,但子类在根本上还是继承了父类

值得注意的是在没有加Target.prototype.constructor = Target;这句话时

console.log(son.constructor);     //Father()

子类的constructor本应是它函数本身,然而这里打印的却Father()

是因为在底部实现了下面的代码:

son.__proto__->new F()                                      //子类实例化的对象指向了“干净的函数”的实例
new F().__proto__->Father.prototype                 //“干净的函数”的实例对象指向父类的原型
Father.prototype.constructor ->Father                //父类原型的构造器就是父类它自己

所以最后打印出来的就是Father()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值