JavaScript中的继承方式

虽然在ES6中有了继承,使用extends关键字就能实现。本篇讲的不是这种,而是ES6之前的几种实现继承的方式。

1、原型链

原理:利用原型让一个引用类型继承另外一个引用类型的属性和方法。

构造函数,原型,实例之间的关系:每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

原型链实现继承例子

function Parent(){
        this.name = 'mike';
    }

    function Child(){
        this.age = 12;
    }
    Child.prototype = new Parent();//Child继承Parent,通过原型,形成链条

    var test = new Child();
    alert(test.age);
    alert(test.name);//得到被继承的属性
    //继续原型链继承
    function Brother(){   //brother构造
        this.weight = 60;
    }
    Brother.prototype = new Child();//继续原型链继承
    var brother = new Brother();
    alert(brother.name);//继承了Parent和Child,弹出mike
    alert(brother.age);//弹出12

2、借用构造函数

原理:在子类型构造函数的内部调用超类构造函数,通过使用call()和apply()方法可以在新创建的对象上执行构造函数。

例子:

<script>
    function Parent(age){
        this.name = ['mike','jack','smith'];
        this.age = age;
    }

    function Child(age){
        Parent.call(this,age);
    }
    var test = new Child(21);
    alert(test.age);//21
    alert(test.name);//mike,jack,smith
    test.name.push('bill');
    alert(test.name);//mike,jack,smith,bill
</script>

借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起,所以我们需要原型链+借用构造函数的模式,这种模式称为组合继承

3.组合继承

例子:

<script>
    function Parent(age){
        this.name = ['mike','jack','smith'];
        this.age = age;
    }
    Parent.prototype.run = function () {
        return this.name  + ' are both' + this.age;
    };
    function Child(age){
        Parent.call(this,age);//对象冒充,给超类型传参
    }
    Child.prototype = new Parent();//原型链继承
    var test = new Child(21);//写new Parent(21)也行
    alert(test.run());//mike,jack,smith are both21
</script>

组合式继承是比较常用的一种继承方法,其背后的思路是 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。

(补充:

call()和apply()都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。

区别:call和apply方法完全一致,只是apply在传参的方式上,它以数组方式来传参。

call()的用法:调用一个对象的一个方法,以另一个对象替换当前对象

语法:apply([thisObj,arg1,arg2,arg3...]);

apply的语法:apply([thisObj [,argArray] ]);

全局函数applycall可以用来改变函数中this的指向,如下:

 // 定义一个全局函数
    function foo() {
        console.log(this.fruit);
    }
    
    // 定义一个全局变量
    var fruit = "apple";
    // 自定义一个对象
    var pack = {
        fruit: "orange"
    };
    
    // 等价于window.foo();
    foo.apply(window);  // "apple",此时this等于window
    // 此时foo中的this === pack
    foo.apply(pack);    // "orange"
    


)

4.原型式继承

例子:

这种继承借助原型并基于已有的对象创建新对象,同时还不用创建自定义类型的方式称为原型式继承

<script>
     function obj(o){
         function F(){}
         F.prototype = o;
         return new F();
     }
    var box = {
        name : 'trigkit4',
        arr : ['brother','sister','baba']
    };
    var b1 = obj(box);
    alert(b1.name);//trigkit4

    b1.name = 'mike';
    alert(b1.name);//mike

    alert(b1.arr);//brother,sister,baba
    b1.arr.push('parents');
    alert(b1.arr);//brother,sister,baba,parents

    var b2 = obj(box);
    alert(b2.name);//trigkit4
    alert(b2.arr);//brother,sister,baba,parents
</script>

原型式继承首先在obj()函数内部创建一个临时性的构造函数 ,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。

5.寄生式继承

例子:

这种继承方式是把原型式+工厂模式结合起来,目的是为了封装创建的过程。

<script>
    function create(o){
        var f= obj(o);
        f.run = function () {
            return this.arr;//同样,会共享引用
        };
        return f;
    }
</script>

组合式继承的小问题

组合式继承是js最常用的继承模式,但组合继承的超类型在使用过程中会被调用两次;一次是创建子类型的时候,另一次是在子类型构造函数的内部

<script>
    function Parent(name){
        this.name = name;
        this.arr = ['哥哥','妹妹','父母'];
    }

    Parent.prototype.run = function () {
        return this.name;
    };

    function Child(name,age){
        Parent.call(this,age);//第二次调用
        this.age = age;
    }

    Child.prototype = new Parent();//第一次调用
</script>

以上代码是之前的组合继承,那么寄生组合继承,解决了两次调用的问题。

6.寄生组合类继承

例子:

基本思想:通过借用函数来继承属性,通过原型链的混成形式来继承方法

<script>
    function obj(o){
        function F(){}
        F.prototype = o;
        return new F();
    }
    function create(parent,test){
        var f = obj(parent.prototype);//创建对象
        f.constructor = test;//增强对象
    }

    function Parent(name){
        this.name = name;
        this.arr = ['brother','sister','parents'];
    }

    Parent.prototype.run = function () {
        return this.name;
    };

    function Child(name,age){
        Parent.call(this,name);
        this.age =age;
    }

    inheritPrototype(Parent,Child);//通过这里实现继承

    var test = new Child('trigkit4',21);
    test.arr.push('nephew');
    alert(test.arr);//
    alert(test.run());//只共享了方法

    var test2 = new Child('jack',22);
    alert(test2.arr);//引用问题解决
</script>

以上就是我总结的六种JavaScript继承的方法!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值