Javascript 構造函數和類


1.構造函數

構造函數的名稱一般都是首字母大寫
掛載在this上面的屬性為實例屬性,實例屬性再每個實例間都是獨立的
原型鏈屬性通過prototype添加,他是所有實例共享的
類方法/靜態屬性只能由構造函數本身訪問
當實例屬性和原型鏈上的屬性重名時,優先訪問實例屬性,沒有實例屬性再訪問原型屬性
大多數瀏覽器的 ES5 實現之中,每一個對象都有__proto__屬性,指向其的構造函數的prototype屬性對象

<script>
    // 創建構造函數
    function Person(name,age){
        // 掛載在this上面的都是實例屬性
        this.name = name
        this.age = age
    }

    // 創建實例
    var p1 = new Person("張三",20)
    var p2 = new Person("李四",18)
    // 訪問實例屬性
    console.log(p1.name,p1.age) //張三 20
    console.log(p2.name,p2.age) //李四 18
    // 修改實例屬性
    p1.age = 25
    p2.age = 23
    console.log(p1.name,p1.age) //張三 25
    console.log(p2.name,p2.age) //李四 23

    // 添加原型鏈屬性/方法(所有實例共享)
    Person.prototype.sayHello = function(){
        console.log(`我的名字是${this.name},今年${this.age}歲`)
    }
    // 訪問原型鏈方法
    p1.sayHello() //我的名字是張三,今年25歲
    p2.sayHello() //我的名字是李四,今年23歲
    // 類方法/靜態屬性(只能由構造函數本身訪問)
    Person.title = "這是構造函數的標題"
    console.log(Person.title) //"這是構造函數的標題"
    console.log(p1.title) //undefined
    console.log(p2.title) //undefined

    // 動態創建實例方法(與原型鏈方法重名)
    p1.sayHello = function(){
        console.log("我是p1的sayHello()")
    }
    // 優先從實例屬性中讀取
    p1.sayHello() //我是p1的sayHello()
    // p2沒有相關實例屬性,所以訪問原型鏈方法
    p2.sayHello() //我的名字是李四,今年23歲

    // __proto__屬性
    console.log(p2.__proto__) //{sayHello: ƒ, constructor: ƒ}
</script>

2.class類

ES6的class可以看作只是一個語法糖,它的絕大部分功能,ES5 都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。
類就是將原先寫在構造函數內部的代碼,寫入到constructor()中
將原先寫在prototype上面的屬性直接寫在類里面
將靜態屬性直接寫在類里面並且在前面添加static關鍵字
類的數據類型就是函數,類本身就指向構造函數

<script>
    // 創建一個類
    class Person{
        // constructor內部的數據是每個實例有獨有一份
        constructor(name,age){
            this.name = name
            this.age = age
        }
        // 原型鏈方法
        sayHello(){
            console.log(`我的名字是${this.name},今年${this.age}歲`)
        }
        // 靜態方法(只能由類本身訪問)
        static foo(){
            console.log("我是類的靜態方法")
        }
        // 靜態屬性(只能由類本身訪問)
        static title = "這是類的標題"
    }
    // 創建實例
    var p1 = new Person("張三",20)
    var p2 = new Person("李四",18)
    // 訪問實例屬性
    console.log(p1.name,p1.age) //張三 20
    console.log(p2.name,p2.age) //李四 18
    // 修改實例屬性
    p1.age = 25
    p2.age = 23
    console.log(p1.name,p1.age) //張三 25
    console.log(p2.name,p2.age) //李四 23

    // 訪問原型鏈方法
    p1.sayHello() //我的名字是張三,今年25歲
    p2.sayHello() //我的名字是李四,今年23歲
    // 類方法/靜態屬性(只能由類本身訪問)
    Person.foo() //"我是類的靜態方法"
    console.log(Person.title) //"這是類的標題"
    console.log(p1.title) //undefined
    console.log(p2.title) //undefined

    // 類的本質
    console.log(typeof Person) //function
    console.log(p1.sayHello === Person.prototype.sayHello) //true
</script>

3.extends 繼承

子類通過extends可以繼承父類的實例屬性和實例方法之外,還可以有自己的實例屬性和實例方法
子類繼承父類的本質,相當於把子類的原型鏈指向了父類

<script>
    // 創建一個類
    class Person{
        // constructor內部的數據是每個實例有獨有一份
        constructor(name,age){
            this.name = name
            this.age = age
        }
        // 原型鏈方法
        sayHello(){
            console.log(`我的名字是${this.name},今年${this.age}歲`)
        }
        // 靜態方法(只能由類本身訪問)
        static foo(){
            console.log("我是類的靜態方法")
        }
        // 靜態屬性(只能由類本身訪問)
        static title = "這是類的標題"
    }
    // Student類繼承Person
    class Student extends Person {
        // name,age,school就是創建時傳入的參數
        constructor(name,age,school){
            // super()是父類的構造器,將name和age傳遞給他
            super(name,age)
            // 添加新的實例屬性,接收school參數(學生這個類有自己的實例屬性)
            this.school = school
        }
        // 添加原型鏈方法
        motto(){
            console.log("好好學習,天天向上")
        }
        // 添加類屬性
        static title = "我是Studnet類的標題"
    }
    // 創建實例
    var stu1 = new Student("小明",16,"藍翔")
    var stu2 = new Student("小強",17,"新東方")
    // 訪問實例屬性
    console.log(stu1.name,stu1.age,stu1.school) //小明 16 藍翔
    console.log(stu2.name,stu2.age,stu2.school) //小強 17 新東方
    // 修改實例屬性
    stu1.age = 20
    stu2.age = 21
    console.log(stu1.name,stu1.age,stu1.school) //小明 20 藍翔
    console.log(stu2.name,stu2.age,stu2.school) //小強 21 新東方

    // 訪問原型鏈方法
    stu1.sayHello() //我的名字是小明,今年20歲
    stu2.sayHello() //我的名字是小強,今年21歲
    stu1.motto() //好好學習,天天向上
    stu2.motto() //好好學習,天天向上

    // 類方法/靜態屬性(只能由類本身訪問)
    console.log(Student.title) //"我是Studnet類的標題"
    console.log(stu1.title) //undefined
    console.log(stu2.title) //undefined

    // 類的本質
    console.log(typeof Student) //function
    console.log(stu1.motto === Student.prototype.motto) //true

    // 子類的原型鏈指向了父類
    console.log(stu1)
    // Student {name: "小明", age: 20, school: "藍翔"}
    // age: 20
    // name: "小明"
    // school: "藍翔"
    // __proto__: Person
</script>

4.ES5構造函數的繼承

在當前構造函數中調用父級構造函數,使用call()方法修改this指向,並將參數傳遞給他,使用他間接為當前this添加實例屬性
將當前構造函數的prototype指向父級構造函數的匿名實例,以便訪問它的原型鏈方法
如果當前構造函數要添加新的原型方法,可以在prototype對象上接着添加

<script>
    // 創建父類構造函數
    function Person(name,age){
        if(name){
            this.name = name
        }
        if(age){
            this.age = age
        }
    }
    Person.prototype.sayHello = function(){
        console.log(`我的名字是${this.name},今年${this.age}歲`)
    }

    // 創建繼承Person的構造函數
    function Student(name,age,school){
        // 掛載實例屬性
        this.school = school
        // 調用Person()並強制綁定this,為實例掛載屬性
        Person.call(this,name,age)
    }
    // 綁定原型鏈為Person的匿名實例
    Student.prototype = new Person()
    // 為Student添加新的原型方法
    Student.prototype.motto = function(){
        console.log("好好學習,天天向上")
    }

    // 創建實例
    var s1 = new Student("李四",25,"藍翔")
    // 訪問實例屬性
    console.log(s1.name,s1.age,s1.school)
    // 訪問Person原型上的方法
    s1.sayHello() //我的名字是李四,今年25歲
    // 訪問Student原型上的方法
    s1.motto() //好好學習,天天向上
</script>


免責聲明!

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



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