JavaScript继续体式格局详解

js继承的观点

js里经常运用的以下两种继承体式格局:

原型链继承(对象间的继承)
类式继承(组织函数间的继承)

因为js不像java那样是真正面向对象的言语,js是基于对象的,它没有类的观点。所以,要想完成继承,能够用js的原型prototype机制或许用applycall要领去完成

在面向对象的言语中,我们运用来建立一个自定义对象。但是js中一切事物都是对象,那末用什么方法来建立自定义对象呢?这就须要用到js原型

我们能够简朴的把prototype看作是一个模版,新建立的自定义对象都是这个模版(prototype)的一个拷贝 (实际上不是拷贝而是链接,只不过这类链接是不可见,新实例化的对象内部有一个看不见的__Proto__指针,指向原型对象)。

js能够经由历程组织函数和原型的体式格局模仿完成类的功用。 别的,js类式继承的完成也是依托原型链来完成的。

原型式继承与类式继承

类式继承是在子范例组织函数的内部挪用超范例的组织函数。
严厉的类式继承并非很罕见,平常都是组合著用:

function Super(){
    this.colors=["red","blue"];
}
 
function Sub(){
    Super.call(this);
}

原型式继承是借助已有的对象建立新的对象,将子类的原型指向父类,就相当于加入了父类这条原型链

原型链继承

为了让子类继承父类的属性(也包含要领),起首须要定义一个组织函数。然后,将父类的新实例赋值给组织函数的原型。代码以下:

<script>
    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
</script>

以上原型链继承还缺乏一环,那就是Object,一切的组织函数都继承自Object。而继承Object是自动完成的,并不须要我们本身手动继承,那末他们的从属关联是如何的呢?

肯定原型和实例的关联

能够经由历程两种体式格局来肯定原型和实例之间的关联。操作符instanceofisPrototypeof()要领:

alert(brother instanceof Object)//true
alert(test instanceof Brother);//false,test 是brother的超类
alert(brother instanceof Child);//true
alert(brother instanceof Parent);//true

只如果原型链中涌现过的原型,都能够说是该原型链派生的实例的原型,因而,isPrototypeof()要领也会返回true

js中,被继承的函数称为超范例(父类,基类也行),继承的函数称为子范例(子类,派生类)。运用原型继承主要由两个题目:
一是字面量重写原型会中缀关联,运用援用范例的原型,而且子范例还没法给超范例通报参数。

伪类处理援用同享和超范例没法传参的题目,我们能够采纳“借用组织函数”手艺

借用组织函数(类式继承)

<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>

借用组织函数虽然处理了适才两种题目,但没有原型,则复用无从谈起,所以我们须要原型链+借用组织函数的形式,这类形式称为组合继承

组合继承

<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()的用法:挪用一个对象的一个要领,以另一个对象替代当前对象。

call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 

原型式继承

这类继承借助原型并基于已有的对象建立新对象,同时还不必建立自定义范例的体式格局称为原型式继承

<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()函数内部建立一个暂时性的组织函数 ,然后将传入的对象作为这个组织函数的原型,末了返回这个暂时范例的一个新实例。

寄生式继承

这类继承体式格局是把原型式+工场形式结合起来,目标是为了封装建立的历程。

<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 = ['哥哥','mm','父母'];
    }

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

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

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

以上代码是之前的组合继承,那末寄生组合继承,处理了两次挪用的题目。

寄生组合式继承

<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>

call和apply

全局函数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"
    



    原文作者:trigkit4
    原文地址: https://segmentfault.com/a/1190000002440502
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞