JS完美收官之——继承发展史

代码复用一直是咱们程序员所追求的远大目标,毕竟能够少写点代码,何乐而不为呢?当说到代码复用的时候,最早想到的是继承,JavaScript对象上有本身的属性,也有一些属性是从原型对象继承来的,下面咱们来看看实现继承的几种方式: 程序员

1.传统模式——原型链闭包

用原型链的继承时,不只继承了自身的属性,并且继承了原型上的属性和方法。函数

看代码:this

//原型链继承
        Grand.prototype.lastName = '鲁班大师';
        function Grand(){
            //隐式连接 __proto__
        }
        var grand = new Grand();
        Father.prototype = grand;
        function Father(){
            this.name = '小鲁班';
             //隐式连接 __proto__
        }
        var father = new Father();

        Son.prototype = father;
        function Son(){
          this.age = 18
            //隐式连接 __proto__
        }
        var son = new Son();

咱们先看下这种继承模式的工做原理: spa

当咱们用new Son()来建立一个对象时,会建立一个图(3),里面保存了age的属性,若是咱们访问lastName属性时,尽管图(3)并无lastName这个属性,可是经过Son()的prototype原型上的隐式属性__proto__能够访问到图(1)中的lastName属性,这个__proto__就是原型链,这个属性只能系统内部去使用,开发者是用不了的。 prototype

咱们还要注意一点:若是咱们在控制台执行,son.name = "长江七号",这个操做并不会改变图(2)里面的name,它会直接在图(3)自身上建立一个属性,以下: 代理

原型链继承弊端:缺点在于同时继承了两个对象的属性,可是在大多的时候咱们并不须要这些属性,由于它们颇有可能指向一个特定的实例,而不是复用。 指针

2.继承——借用构造函数 code

借用构造函数的方式并不能彻底说是继承,就是借别人的方法来用下。对象

function Person(name,age,sex){
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        function Student(name,age,sex,grande){
            Person.call(this,name,age,sex);
            this.grande = grande;
        }
        var student = new Student();

当咱们要构造一个Student的构造函数,可是Person已经实现了咱们部分功能,因此在Student中咱们能够用Person中的方法就能够了。

借用构造函数弊端:

1.只能继承在构造函数中的方法,却不能继承那些添加到原型中的方法。

2. 这种继承每次要多调用一个函数,只是在视觉上省代码,实际运行上还浪费效率了。

3.共享原型

共享原型的方式简单粗暴,让一个原型同时给两个函数,从而达到继承的目的,如图:

看代码:

Father.prototype.name = "长江七号" 
        function Father(){
            var age = 18;
        }
        function Son(){
            var sex = 'famle';
        }
        function inherit(Target,Origin){
            Target.prototype = Origin.prototype;
        }
        inherit(Son,Father)
        var son = new Son();
        var father = new Father();

尽管这两个对象共享了同一个原型,访问值的时候也很快,可是,这同时也是一个缺点,若是子对象修改了一个原型的属性,那么它会影响全部的祖对象。咱们没有办法给子对象的原型单独给加属性。

属性修改过程:

以上三种继承方法多多少少都存在点缺点,接着引出第四种完美方法:

4.圣杯模式

圣杯模式其实跟共享原型的思路差很少,它是经过剪断父对象跟子对象的原型之间的直接关系,从而解决共享原型这一方法产生的问题,同时还能够继续共享原型上的属性,但改变子对象上原型的属性时,祖对象原型不受影响。如图所示:

看代码:

Father.prototype.name = "长江七号" 
        function Father(){
            var age = 18;
        }
        function Son(){
            var sex = 'famle';
        }
        function inherit(Target,Origin){
            function F(){};//中间空白函数代理
            F.prototype = Origin.prototype;
            Target.prototype = new F();
        }
        inherit(Son,Father)
        var son = new Son();
        var father = new Father();

⚠️注意:写圣杯模式的时候,咱们必定要注意第10行和第11行,它们两个位置必定不能写反,必须在new以前改变原型指向,不然原型指向就指原来的自身原型上。**

接下来咱们试试看好很差使:

ok!好使没问题,咱们的目的达到了,几乎完美了,可是还差点,咱们还须要重置构造函数指针,,若是不重置,那么全部子对象都会显示Father()是它们的构造函数,形成指向紊乱了,因此咱们能够归下位:

Father.prototype.name = "长江七号" 
        function Father(){
            var age = 18;
        }
        function Son(){
            var sex = 'famle';
        }
        function inherit(Target,Origin){
            function F(){};
            F.prototype = Origin.prototype;
            Target.prototype = new F();
            Target.prototype.constructor = Target;//重置构造函数
        }
        inherit(Son,Father)
        var son = new Son();
        var father = new Father();

若是有一天咱们想知道这个子对象真正继承自谁,在上面的基础上,咱们还能够添加一个指向原始父对象的引用,加一个属性uber,原本是能够用"super"的,可是因为super是保留字的关键字。改进后以下代码:

Father.prototype.name = "长江七号" 
        function Father(){
            var age = 18;
        }
        function Son(){
            var sex = 'famle';
        }
        function inherit(Target,Origin){
            function F(){};
            F.prototype = Origin.prototype;
            Target.prototype = new F();
            Target.prototype.constructor = Target;//重置构造函数
            Target.prototype.uber = Origin.prototype;//访问超类,真正继承于谁
        }
        inherit(Son,Father)
        var son = new Son();
        var father = new Father();

其实还有一种写法,在雅虎的YUI库里面有个inherit方法:利用闭包的私有化属性

Father.prototype.name = "长江七号" 
        function Father(){
            var age = 18;
        }
        function Son(){
            var sex = 'famle';
        }
        // function inherit(Target,Origin){
        //     function F(){};
        //     F.prototype = Origin.prototype;
        //     Target.prototype = new F();
        //     Target.prototype.constructor = Target;
        // }
        var inherit = (function(){
            var F = function(){};
            return function (Target,Origin){
                F.prototype = Origin.prototype;
                Target.prototype = new F();
                Target.prototype.constructor = Target;
            }
        }());
        inherit(Son,Father)
        var son = new Son();
        var father = new Father();

『 好啦,以上呢就给你们的分享啦,若是您以为本篇内容有帮助到你,能够转载但记得要关注,要标明原文哦,谢谢支持~』

「欢迎各位大佬关注我,扫二维码便可」

相关文章
相关标签/搜索