JavaScript — 理解prototype與class

一步一步捋清prototype

前言

  • 學習JavaScript,不可避免地要學習JS中的面向對象的編程模式,但JS中的OOP和c++,java等典型的面嚮對象語言明顯不一樣,「原型鏈」,es6中的「class」,都彰顯着js中面向對象的不同凡響。
  • 究竟什麼是原型prototype呢?如何在JavaScript中實現「類」呢?

一張圖

圖片描述

圖片分析

這是我總結的一張圖片,簡單的描繪了原型和構造函數、實例間的複雜關係。java

  1. 全局對象window屬性Object(此處僅用來舉例,其他屬性暫且不提),指向Object()這個函數對象
  2. Object中存着prototype,它指向了原型(原型中包含了對象的全部方法和屬性)
  3. 當咱們聲明一個實例let obj = new Object(), 你能夠發現它天生就帶着__proto__屬性。而__proto__居然和Object.prototype指向了同一個對象。咱們知道,它就是原型
    clipboard.png

一些思考

1.Object.prototype(即對象的原型)的原型是什麼呢?c++

  • 咱們不妨打印出來試一試:clipboard.png
    應該和你想的同樣,對象的原型就是原型鏈的盡頭了,它只是一個普通的對象,並無原型。

2.Object.prototype中的constructor是什麼?有什麼用?es6

  • 你應該還記得咱們剛剛像這樣let obj = new Object();建立了一個對象實例obj,那麼再來看看這個,你應該就一目瞭然了
    clipboard.png
    沒錯,constructor存在的意義就是爲了讓實例化地對象找到它的構造函數。(對實例化的數組,constructor指向Array;對實例化地函數,constructor指向Function)

3.但你不能人爲constructor指向的必定是構造出當前對象的函數。編程

  • 例如,你能說出Object.prototype.constructor指向誰嗎?clipboard.png
    你看,這個結果是否是很讓人頭大??Object.prototype指向了原型,而原型的constructor的又指回了Object。實際上這種試驗是無心義的,由於咱們要知道,constructor是提供給實例,用來定位它的構造函數的屬性,而不是給原型自己使用的。
  • 而這種Object.prototype.constructor ===Object的現象,其實源於人爲設計。爲了讓實例的對象都繼承原型中的constructor,沒法避免出現這種現象。

4.咱們嘗試更深刻一些?嘗試剖析一下數組對象的相關結構。數組

  • 問題1:Array.prototype.__proto__===?函數

    • 直接來看結果吧clipboard.png
    • 爲何會有這種結果呢?其實咱們只須要理解清Array.prototype的本質就行了,其實Array.prototype只是一個Object()構造出的對象實例而已,一個對象實例的原型固然是Object.prototype啊!換句話說Array.prototype和obj在本質上是同樣的!
  • 問題2:let arr=[1,2,3]; clipboard.png 屬於對象的方法hasOwnProperty是如何在數組實例上生效的呢?學習

    1. arr在自身尋找hasOwnProperty方法,發現沒有。
    2. arr又到他爸爸arr.__proto__即Array.prototype中尋找hasOwnProperty方法,仍然找不到 =
    3. arr再到他爺爺arr.__proto__.__proto__即Object.prototype中尋找,找到了這個方法,因而arr調用了這個方法。

類和繼承

  1. class的默認屬性this

    class Person {
       name = 'Oliver'
       sayHi = ()=>{ console.log(hi) }
    }

    在class聲明中
    經過 = 賦值的屬性,會變成該class實例的屬性默認值;
    經過箭頭函數聲明的方法,會掛載到該實例身上,而非class身上。spa

  2. 方法的重寫prototype

    // Person定義同上
    class Child extends Person{
       sayHi(){
           console.log('I am a child.')
           super.sayHi()
       }
    }

    子類重寫父類的方法後,若是還想調用父類的方法,須要使用 super 關鍵字,super上掛載有父類的原始方法。

  3. class vs prototype

    // prototype方法
       function Person( name, age) {
              this.name = name,
               this.age = age
       }
       Person.prototype.sayHi = function() {
           console.log('你好,我叫'+this.name);
       }
       
       //class方法
    class Person{
       constructor(name,age){
           this.name = name;
           this.age = age;
       }
       sayHi(){ console.log('你好,我叫'+this.name); }
    }
  4. 繼承

    class Children extends Person{
        constructor(name,age,grade){
            super(name,age);
            this.grade = grade;
        }
        sayGrade(){
            console.log('我今年${grade}年級');
        }
    }

conclusion

  • class只是prototype方法的語法糖而已,本質上沒有區別
  • 運用順序:理解prototype => 熟練使用prototype => 無壓力使用class
相關文章
相關標籤/搜索