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();

『 好啦,以上呢就給你們的分享啦,若是您以爲本篇內容有幫助到你,能夠轉載但記得要關注,要標明原文哦,謝謝支持~』

「歡迎各位大佬關注我,掃二維碼便可」

相關文章
相關標籤/搜索