1. 程式人生 > 其它 >JavaScript面向物件三大特性之一:繼承性

JavaScript面向物件三大特性之一:繼承性

文章目錄


一.什麼是繼承性

通常來說繼承就類似於兒子繼承父親的財產,但這樣說明並不準確,因為這代表父親將財產給了兒子,父親自己就沒有了,但在JavaScript面向物件中,繼承更像師傅與徒弟的關係,師傅將一生所學教給了徒弟,徒弟學會了,但是師傅也沒有失去什麼,這就是JavaScript面向物件中的繼承性。




二.繼承方法

接下來看有幾種繼承方式,和它們的利弊:

1.原型鏈繼承

      function GaoBW() {
            this.fang = '大別也'
; this.che = '五菱巨集光'; } function Parent(n, m) { this.name = n this.age = m } Parent.prototype = new GaoBW() var tc = new Parent('王鐵錘', 30) console.log(tc.name, tc.age, tc.fang, tc.che); console.log(tc.constructor)
;

原理:將Parent的原型物件指向GaoBW ,這樣Parent的例項化物件也能繼承GaoBW的屬性

缺點:這麼做,會存在繼承鏈紊亂,tc是通過建構函式Farent()創建出來的。但是繼承過以後,會發現,tc的建構函式,不在Farent,而是GaoBW

解決辦法:手動的糾正繼承鏈

        Parent.prototype.constructor = Parent

最終得到的結果:
Parent的例項化物件繼承到了GaoBW的屬性,並且也證明了是Parent的例項化物件
在這裡插入圖片描述

2.使用prototype直接繼承

        function GaoBW() {
        }
GaoBW.prototype.fang = '大別也'; GaoBW.prototype.che = '五菱巨集光'; function Parent(n, m) { this.name = n this.age = m } Parent.prototype = GaoBW.prototype Parent.prototype.constructor = Parent var tc = new Parent('王鐵錘', 30) var gao = new GaoBW() Parent.prototype.fang = '貧民窟' console.log(tc.name, tc.age, tc.fang, tc.che); console.log(gao.fang); console.log(tc.constructor); </script> </body>

效果:可以讓Parent()跳過 GaoBW(),直接繼承GaoBW.prototype

優點:效率比較高(不用執行和建立Person的例項了)
缺點:
1、依然會產型繼承鏈紊亂,需要修改繼承鏈
​ 2、因為Paretn的原型物件指向了GaoBw的原型物件,所以Paretn修改原型物件的值,GaoBw原型物件的值也被修改了,(繼承者修改繼承的屬性時,被繼承者的屬性也會被篡改,非常不合理)


3.利用空物件作為中介

function GaoBW() {}
        GaoBW.prototype.fang = '大別也';
        GaoBW.prototype.che = '五菱巨集光';

        // 建立一個空的建構函式 讓這個空的建構函式的原型物件接受GaoBW原型物件的屬性
        // 然後在讓Parent的原型物件指向F的例項化物件,這樣Parent在改變繼承的內容時,GaoBW的屬性就不在收影響了
        function F() {}
        F.prototype = GaoBW.prototype

        function Parent(n, m) {
            this.name = n
            this.age = m
        }

        Parent.prototype = new F()
        Parent.prototype.constructor = Parent
        var tc = new Parent('王鐵錘', 30)
        var gao = new GaoBW()
        tc.fang = '貧民窟'
        console.log(tc.name, tc.age, tc.fang, tc.che);
        console.log(gao.fang);

效果:建立一個空的建構函式 讓這個空的建構函式的原型物件接受GaoBW原型物件的屬性
然後在讓Parent的原型物件指向F的例項化物件,這樣Parent在改變繼承的內容時,GaoBW的屬性就不在收影響了

封裝方法
將利用空建構函式當中介的方法封裝方便使用

function GaoBW() {}
        GaoBW.prototype.fang = '大別也';
        GaoBW.prototype.che = '五菱巨集光';

        function Parent(n, m) {
            this.name = n
            this.age = m
        }

        //  將建立空建構函式的方法封裝為一個函式,直接呼叫 使用
        function fz(Gao, Par) {
            function F() {}
            F.prototype = Gao.prototype
            Par.prototype = new F()
            Par.prototype.constructor = Par
        }
        fz(GaoBW, Parent)
        var tc = new Parent('王鐵錘', 30)
        var gao = new GaoBW()
        tc.fang = '貧民窟'
        console.log(tc.name, tc.age, tc.fang, tc.che);
        console.log(gao.fang);

三.建構函式繫結 call&&apply

1.call方法
語法: 被繼承者.call(this,如果屬性直接用有不需要傳值,這裡就只寫this就行,否則就寫需要傳的值)

 function GaoBW() {
            this.name = '高百萬';
            this.age = 100;
        }
        // 不能繼承原型物件的屬性
        GaoBW.prototype.chezi = '五菱巨集光'

        function Son() {
            this.fang = '租房';
            this.che = '寶馬';
            GaoBW.call(this)
        }

        var son1 = new Son()
        console.log(son1.name, son1.age, son1.chezi);

缺點:call只能繼承被繼承者自身的屬性,不能繼承prototype的屬性

2.apply

apply與call的繼承方法和機制相同,不同點就在於apply在傳值時需要在寫一個[],在[]內傳值,而call直接用,隔開傳值

 function GaoBW() {
            this.name = '高百萬';
            this.age = 100;
        }
        // 不能繼承原型物件的屬性
        GaoBW.prototype.chezi = '五菱巨集光'

        function Son() {
            this.fang = '租房';
            this.che = '寶馬';
            GaoBW.apply(this)
        }

        var son1 = new Son()
        console.log(son1.name, son1.age, son1.chezi);

3.組合繼承

1.組合繼承也叫偽經典繼承
2.將原型鏈繼承和建構函式繼承組合在一塊
3.原型鏈實現對原型屬性和方法的繼承
4.借用建構函式實現對例項屬性的繼承

解決了call和apply只能繼承建構函式本身的屬性的問題

 function GaoBW() {
            this.name = '高百萬';
            this.age = 30;

        }
        GaoBW.prototype.value = 100

        function Parent() {
            this.name1 = '閻濤';
            this.age1 = 19;
            GaoBW.call(this)
        }
        Parent.prototype = new GaoBW()
        Parent.prototype.constructor = Parent
        var par = new Parent()
        par.name = '高千萬'
        var gao = new GaoBW()
        console.log(gao.name);
        console.log(par.name, par.age, par.value);
        console.log(par.constructor);

四.原型鏈

1.當物件訪問屬性和方法的時候,會往自身查詢,如果沒有才會去原型中找。(一級一級傳遞 形成了原型鏈)
2.先從自身找,自身沒有像父元素找,父元素沒有像object找,object沒有報錯
3.原型鏈遵循就近原則,會先從離得近的找

        function Person() {

        }
        Person.prototype.sayname = function() {
            console.log('我是person原型物件的sayname')
        }
        Object.prototype.sayname = function() {
            console.log('我是object原型物件的sayname')
        }

        var p1 = new Person();
        p1.sayname = function() {
            console.log('我是person例項物件物件的sayname')
        }
        p1.sayname();