JS三大特性


抽象

在分析三大特性之前我們要先了解什么叫抽象。

定義:

在定義一個類的時候,實際上就是把一類事物的共有的屬性和行為提取出來,形成一個物理模型(模板),這種研究問題的方法就稱為抽象

一、封裝

定義:

就是把抽象出來的屬性和對屬性的操作封裝在一起,屬性被保護在內部,程序的其他部分只能通過特定的操作(函數),才能對屬性進行操作。

公開屬性和私有屬性

<script>

    function Person(in_name, in_age, in_sql) {
        this.name = in_name;
        var age = in_age;
        var sql = in_sql;
    }

    var p1 = new Person("haha", 20, 1000)
    alert(p1.name)

</script>

結果:

image

但是此時我們訪問,age和sql:

<script>

    function Person(in_name, in_age, in_sql) {
        this.name = in_name;
        var age = in_age;
        var sql = in_sql;
    }

    var p1 = new Person("haha", 20, 1000)
    alert(p1.age)

</script>

結果:

image

說明:

這里我們就看到了name是公開屬性,而age和sql則是私有屬性

問題:屬性有公開屬性和私有屬性,那方法有沒私有和公開之分那?

類中的公開方法有個別名特權方法,私有方法有個別名內部方法

公開方法

<script>

        function Person(in_name, in_age, in_sql) {
            this.name = in_name;  // 公開屬性
            var age = in_age;  // 私有屬性
            var sql = in_sql;  // 私有屬性

            // 在類中如何定義公開方法(特權方法);私有方法(內部方法)
            // 如果我們希望操作私有的屬性,則可用公開方法實現
            this.show = function () {
                alert(age + "" + sql)
            }
        }

        var p1 = new Person("haha", 20, 1000)
        p1.show();

    </script>
公開方法

結果:

image

說明:

外部要想操作私有屬性,可以通過公開方法來實現

私有方法

<script>

        function Person(in_name, in_age, in_sql) {
            this.name = in_name;  // 公開屬性
            var age = in_age;  // 私有屬性
            var sql = in_sql;  // 私有屬性

            // 私有方法
            function show2() {
                alert(age + ' ' + sql)
            }

        }

        var p1 = new Person("haha", 20, 1000)
        p1.show2();  // 這樣調用會報錯!

    </script>
私有方法

說明:

私有方法同樣可以使用同 中的私有屬性,但是私有方法在外部卻無法被操作。

 

上面的方法,在每次實例化對象的時候,會為每個對象生成一次,即每個對象中都有一個類似的方法,在一定程度上會造成資源浪費。

原型對象 prototype

因此我們想到 原型對象(prototype) 的基礎上添加方法,間接的效果也讓讓每個對象也具有這個方法,這樣操作只讓方法在類中存一份,不會在每個對象中儲存。

但是這個樣處理,也有小問題;即不能調用私有變量和私有方法。

定義的方法操作公有屬性:

<script>

        function Person() {
            this.name = "abc";
            var age = 90;
        }

        Person.prototype.fun1 = function() {
            alert(this.name);
        }

        var p1 = new Person();
        p1.fun1();  // 結果:彈出abc

    </script>
公有屬性

定義的方法操作私有屬性:

<script>

        function Person() {
            this.name = "abc";
            var age = 90;
        }

        Person.prototype.fun1 = function() {
            alert(age);
        }

        var p1 = new Person();
        p1.fun1();  // 結果:報錯 age is not defined(…)

    </script>
私有屬性

操作私有方法和公有方法:

<script>

        function Person() {
            this.name = "abc";  // 公有屬性
            var age = 90;  // 私有屬性
            // 共有方法
            this.show1 = function() {
                alert("haha")
            }
            // 私有方法
            function show2() {
                alert("xxx")
            }
        }

        Person.prototype.fun1 = function() {
            this.show1();  // 正確

            show2();  // 報錯
        }

        var p1 = new Person();
        p1.fun1();

    </script>
操作方法

二、繼承

問題:為什么需要繼承?

最直接的回答,解決代碼冗余。

 

需求:學生交學費,中學生打8折;小學生打5折,然后通過打印的方法,顯示學生的名字、年齡記應繳學費。

我們初步的代碼:

<script>
        // 中學生
        function MidStu(name,age) {
            this.name = name;
            this.age = age;
            this.show = function() {
                alert(this.name + ' ' + this.age);
            }

            // 計算學費
            this.payFee = function(mon) {
                alert("應繳" + mon*0.8);
            }
        }

        // 小學生
        function PupStu(name,age) {
            this.name = name;
            this.age = age;
            this.show = function() {
                alert(this.name + ' ' + this.age);
            }

            // 計算學費
            this.payFee = function(mon) {
                alert("應繳" + mon*0.5);
            }
        }

    </script>

可以看出兩個類型學生代碼中有很多相同的代碼,出現了代碼冗余的問題。

問題:怎么解決上面的代碼冗余?

抽象出一個學生類(即,把兩類學生共性取出來形成的類);然后通過繼承的方式處理。

<script>
        // 抽象出兩類學生共性的類
        function Stu(name, age) {
            this.name = name;
            this.age = age;
            this.show = function() {
                alert(this.name + ' ' + this.age);
            }
        }

        // 中學生
        function MidStu(name,age) {
            // js實際上是通過對象冒充來實現繼承的。
            this.stu = Stu;
            this.stu(name, age);  // 這段代碼很重要,如果沒有它則繼承就失敗了

            // 計算學費
            this.payFee = function(mon) {
                alert("應繳" + mon*0.8);
            }
        }

        // 小學生
        function PupStu(name,age) {
            this.stu = Stu;
            this.stu(name, age);

            // 計算學費
            this.payFee = function(mon) {
                alert("應繳" + mon*0.5);
            }
        }

        // 測試繼承
        var midStu = new MidStu("haha", 30);
        midStu.show();

    </script>
繼承

結果:

image

結果我們發現,我們的MidStu中並沒show方法,但是我們結果卻能調用。

說明:

js的繼承實際上是通過對象冒充來實現的。

js對象繼承的關鍵點:

  • this.stu = Stu;這里相當於將整個Stu函數賦值給stu;賦值的是內存中的索引。此時如果alert(this.stu)的話;會將Stu的整個函數打印出來
  • image

 

  • this.stu(‘xxx’, 20):這段代碼相當重要,關乎繼承能否成功,前面我們知道,第一步只是接收了Stu的內存中的索引,這步的執行,就相當於將Stu的屬性和方法,具體的賦給MidStu。

總結:

1、這里體現了js是動態語言的特性,在執行的過程中開辟內存空間。

2、js的繼承是通過對象冒充來完成的。

3、js可以實現多重繼承,雖然很少用,但是它具備這個功能。

4、Object類是js所有類的基類。

多態

定義:

指一個引用(類型)在不同情況下的多種狀態。

js實際上是舞台的,是一種動態語言,一個變量的類型是在運行的過程中有js引擎來決定的,所以,也可以說js天生就支持多態。

典型案例:

<script>

        function Person() {
            this.test = function() {
                alert("Person");
            }
        }

        function Dog() {
            this.test = function() {
                alert("Dog");
            }
        }

        var v = new Person();
        alert(v.constructor);

        v = new Dog();
        alert(v.constructor);

    </script>
多態

通過打印對象的構造函數來判斷對象的類型。v會隨着對象的創建,而變化類型。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM