js里的继承方式

js里的继承

主要是依赖原型链来实现的。

1.原型链继承

构造函数、原型和实例之间的关系为:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针,让这个原型对象(子的原型)等于要继承的引用类型(父)的实例,通过层层指向关系就可以实现原型链。

原型链继承实现的额本质是重写原型对象,代之以一个新类型的实例。换句话说,原来存在于父类(SuperType)实例中的所有属性和方法,现在也存在于子类的prototype(SubType.prototype)中。在确认继承关系之后,我们给SubType.prototype添加一个方法,这样就在继承了SuperType的属性和方法的基础上又添加了一个新的方法。
原型链的继承是由外向内的,通过通过__proto__属性连接,形成链式。
原型链继承是通过prototype原型属性实现继承。

//父对象,构造函数通常用大写开头区别于普通函数
    function Person(a){
        this.name=a;
        this.age=null;
        this.sex ="男";
        this.sleep = function () {
            return "睡觉";
        }
    }
 //子对象
    function Student(){
    	this.job="学生";
    }
 //原型链继承
  console.log(Student.prototype);//结果为图1
  Student.prototype=new Person("素文");  
  console.log(Student.prototype);//结果为图2
  //实例化对象
  var student=new Student();
  console.log(student);//结果为图3
  
  console.log(student instanceof Student);//true子类对象的实例是自身
  console.log(student instanceof  Person);//true子类对象的实例是父类

图1图1

图2图二
图3图三

1.1原型链继承的特点:

子类的实例继承后包含自身的实例属性,父类里面的构造属性和方法以及父类的原型属性和方法。

1.2原型链继承的缺点:

  • 不能继承子类的原型属性和方法,这里的原型属性和方法被父类的覆盖了(如图1与图2所示)。
  • 只能进行单继承,不能多继承
  • 继承之后,原型对象上的属性全是共享的。
  • 子类不能直接向父类传递参数(指的是不能在实例化子类对象的时候传递参数,只能在原型链继承父类的时候传递)

2.构造函数继承

2.1实质:在子类型构造函数的内部调用超类型构造函数。

这里注意理解,**函数是在特定环境中执行代码的对象。**因为其是对象所以可以通过apply和call方法,在新创建的对象上执行(父类)构造函数(这里使用的是上述两个方法替换对象参数实现的继承,即将父类的实例内容添加子类原型链中)。

//父类
	function Plan(){
        this.name=arguments[0];
        this.water= function () {
            console.log("储水");
        }
    }
//父类
    function Type(t) {
        this.type=t;

    }
//子类
    function Flower(sun,n,t){
        this.sunlike=sun;

        Plan.apply(this,[n]);//第二个参数是集合型
        Type.call(this,t);//第二个参数是序列型
    }
    var flower = new  Flower(false,"剑兰","花");
    console.log(flower);//图4
    
    console.log(flower instanceof  Flower);//true
    console.log(flower instanceof  Plan);//false
    console.log(flower instanceof  Type);//false

图1

图4

2.2特点:

  • 可以实现多继承。
  • 可以向父类传递参数。
  • 构造继承 无法继承父类里的原型属性。
  • 子类的实例是本身,不是父类。

3.实例继承:

在子类内部直接构造父类的实例。

//父类
	function Person(n,s){
        this.name=n;
        this.sex=s;
        this.sleep= function(){
            return "八小时";
        }

    }
 //子类
    function Child(n,s){
        return new Person(n,s);
    }
	
	var child=Child();//调用方式1
	console.log(child);
    var child=new Child("悦雯","女");//调用方式2
    console.log(child);
    console.log(child instanceof Person);//true
    console.log(child instanceof  Child);//false

3.1实例继承的特点

  • 不限定调用的方式。既可以使用函数调用的方式,也可以使用实例化对象的方式。
  • 可以直接由子类向父类传递参数。
  • 子类的实例是父类而不是子类本身。
  • 子类的原型对象还是自身默认的原型对象。
  • 不能渠道子类的构造属性和方法,可以取到父类的构造属性与方法。

4.拷贝继承

4.1实质:

将父类里的属性和方法拷贝给子类。具体为在子类中实例化父类对象,将父类的实例化属性和方法通过遍历拷贝给子类的原型对象。
    function Animale(){
        this.name=arguments[0];
        this.sleep= function () {
            return "睡觉";
        }
    }
    function Type(){
        this.type = arguments[0];
    }
    function Cat(n,s,t){
        this.sex=s;
        this.eat= function () {
            return "进食";
        }
		 Cat.prototype.weight="5kg";
        //拷贝继承
        var animale = new Animale(n);
        for (var key in animale)
        {
            Cat.prototype[key]=animale[key];
        }
        var type = new Type(t);
        for(var key in type)
        {
            Cat.prototype[key]=type[key];
        }
        
    }

    var cat = new Cat("小黑","公","猫科");
    console.log(cat);//结果如图5所示
    console.log(cat instanceof Cat);//true
    console.log(cat instanceof Type);//false
    console.log(cat.__proto__);//自身的原型属性和方法
    console.log(cat.__proto__.__proto__);//objec的原型属性和方法

图5
图5

4.2特点:

  1. 可以支持多继承。
  2. 子类对象的实例是它本身,而不是父类。
  3. 可以向父类传递参数。
  4. 继承的时候需要不断的实例化父类对象,占内存。

5.组合继承:

5.1实质:

原型链继承+构造继承

	function Person(n){
        this.name=n;
        this.eat= function () {
            return this.name+"吃饭";
        }
    }
    Person.prototype={
        constructor:Person,
        color:null
    }
    function Child(a,s,n)
    {
        this.age=a;
        this.sex=s;
        this.sleep= function () {
            return "睡觉";
        }
        Person.call(this,n);//构造
    }
    Child.prototype=new Person("阳");//调用了两次父类的构造函数
    var child=new Child(14,"男","朝阳");
    console.log(child);//图6
    console.log(child instanceof Person);

图六
图6

5.2特点:

  1. 可以实现多继承
  2. 可以向父类传递参数。
  3. 没有实现原型对象属性的共享。(当有同名的方法或属性,换句话说,在实例中有的方法和属性,在原型对象中也有,在读取时会先从实例中找,然后再原型对象中找。如果实例中找到了,就不会再看原型对象。)
  4. 子类的实例既是本身也是父类。
  5. 父类的构造函数在一次子类实例化中要执行两次。

6.寄生组合继承

6.1实质

改进组合继承中,两次调用父类构造函数的缺点。将父类的继承分成两部分,即父类的实例属性和方法及父类的原型属性和方法,两部分分开继承。父类的实例属性和方法用构造继承,父类的原型属性和方法,利用寄生继承。

原理:将父类的原型对象给一个空对象的prototype,再把空对象和子类的原型对象关联。

	function Person(n){
        this.name=n;
        this.sleep= function () {
            return this.name+"睡觉";
        }
    }
    Person.prototype={
        constructor:Person,
        color:null
    }

    function Child(a,n){
        this.age=a;
        this.eat= function () {
            return this.name+"吃饭";
        }
        Person.call(this,n);//构造继承
    }
    //寄生,自执行函数
    (function(){
        var fn= function () {};//空对象
        fn.prototype=Person.prototype;
        Child.prototype=new fn();
        Child.prototype.weight="45kg";

    })();
    var child= new Child(13,"宋询");
    console.log(child);
    console.log(child instanceof Child);//true
    console.log(child instanceof Person);//true

在这里插入图片描述
图6

6.2特点

  1. 可以在子类实例化的时候向父类传递参数。
  2. 只调用一次父类构造函数,也避免了在子类的原型对象上创建不必要的属性。
  3. 可以在寄生过程中为子类添加原型属性。

总的来说,寄生组合式继承是引用类型最理想的继承范式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值