面向對象特徵之封裝-Es6中Class私有和受保護的屬性及方法

熟悉面向對象編程的都知道,面向對象編程最重要的原則之一 - 從外部接口劃份內部接口。也就是說,針對某一類事物,咱們其實並非那麼在意其內部到底是怎樣去實現的,只關心怎樣使用而已。

爲了理解這點,讓咱們先來看看現實生活中的列子。一般,咱們使用的設備很是複雜。可是從外部接口界定內部接口容許使用它們沒有什麼問題。列如一輛汽車。從外面看主要有:輪子、車身、車頂、方向盤等。
汽車外部組成程序員

可是,內部...
汽車內部結構圖編程

有許多的細節,可是咱們並不用去知道這些細節,也能夠很好地開車車。ide

汽車很是可靠,不是嗎?咱們可使用不少年,只有在出現問題時才能使用它 - 進行維修。汽車的可靠性和使用的簡單性在於隱藏內部細節。this

若是咱們從汽車上取下發動機,那麼使用它將會複雜得多(安裝在哪?),而且危險(它能夠電擊)。spa

因此,面向對象編程就相似於汽車同樣。code

內部和外部接口

在面向對象的編程中,屬性和方法能夠分爲兩組:對象

  • 內部接口-方法和屬性,能夠從類的其餘方法訪問,但不能從外部訪問
  • 外部接口-方法和屬性,也能夠從外部訪問

若是咱們繼續與汽車進行類比 - 內部隱藏的部分:發動機、變速器、半軸等 - 是其內部接口。對於對象的運行,內部接口是很是有用的,其細節互相使用。例如,彈性元件鏈接到減震器。blog

可是從外面看,汽車被外層車殼保護着,因此沒有人能夠接觸到。細節隱藏且沒法訪問。咱們能夠經過外部接口使用它的功能。因此,咱們在使用一個對象的時候,並不關心它內部是怎樣工做的。繼承

在JavaScript中,有兩種類型的對象字段(屬性和方法):接口

  • 公共的:隨處均可訪問,它們包含外部接口,咱們在開發中一直經常使用的也就是公共的屬性和方法了
  • 私有的:僅在類的內部可訪問,主要用於內部接口

在許多其餘語言中,還存在「受保護」字段:只能從類內部訪問和擴展它們。它們對內部接口也頗有用。它們在某種意義上比私有更普遍,由於咱們一般但願經過繼承類來獲取和訪問它們。

受保護的字段不是在JavaScript語言級別上實現的,但實際上它們很是方便,咱們也能夠模擬地去實現它們。如今咱們用JavaScript來製做一臺具備這些類型屬性的汽車。

class MBWCar{
    oilAmount = 0; // the amount of oil inside
    constructor(power){
        this.power = power
        alert( `Created a mbw-car, power: ${power}` );
    }
}
// create the mbw car
let mbwCar = new MBWCar(100)

// oil water
mbwCar.oilAmount = 200

從上面的代碼能夠看出oilAmountpower這兩個屬性是公共的,咱們能夠在外部輕易地設置以及獲取它們。

讓咱們將oilAmount屬性更改成protected以對其進行更多控制。例如,咱們不但願任何人將其設置爲零如下。

受保護的屬性一般如下劃線_爲前綴

這不是在語言層面強制去執行,但我們程序員之間有一個衆所周知的慣例,即不該該從外部訪問這些屬性和方法。

class MBWCar{
    _oilAmount = 0;

    constructor(power){
        this._power = power

    }

    set oilAmount(value){
        if (value < 0) throw new Error("Negative oil");
        this._oilAmount = value
    }

    get oilAmount(){
        return this._oilAmount
    }
}
// create the mbw car
let mbwCar = new MBWCar(100)

// oil water
mbwCar.oilAmount = -10 //Error Negative oil

如今訪問受到控制,所以將油量設置爲零如下將失敗。

那麼咱們能夠把power屬性設置爲只讀屬性,這在一些程序開發中也有相似的須要,某些屬性只讀不可更改其值。

class MBWCar{
    constructor(power){
        this._power = power

    }
    get power(){
        return this._power
    }
}
// create the mbw car
let mbwCar = new MBWCar(100)
alert(`Power is: ${mbwCar.power}W`); // Power is: 100W

mbwCar.power = 25 // Error (no setter)

getter/setter方法

class Car{
    _oilMount = 0;
    setOilMount(value){
        if(value<0) throw Error('Negative oil')
        this._oilMount = value
    }
    getOilMount() {
        return this._oilMount;
    }
}
let mbw = new Car()
mbw.setOilMount(100);
alert(mbw.getOilMount());

受保護的屬性是能夠繼承的

若是咱們繼承類MBWCar擴展Car,那麼沒有什麼能阻止咱們重新類的方法中訪問this._oilMount 或this._power屬性。
因此受保護的屬性是能夠繼承的,不像接下來咱們所說的私有屬性。

私有字段

這是JavaScript後面新增的一個針對類屬性的語法。JavaScript引擎不支持,或者部分支持,須要進行polyfilling
在JavaScript的提議中,有一個已完成的標準,爲私有屬性和方法提供語言級支持。

私有的私有字段與#開頭,僅在類的內部可進行訪問.

class Car{
    #oilLiMit = 100;

    #checkOil(value){
        if(value<0) throw Error(`Negative oil`)
        if (value > this.#waterLimit) throw new Error("Too much oil");
    }
}

let car = new Car();

// can't access privates from outside of the class
car.#checkOil(); // Error
car.#waterLimit = 1000; // Error

class BWMCar extends Car{
    method() {
        alert( this.#oilLiMit ); // Error: can only access from Car
    }
}

私有字段不可以經過this[name]去訪問

class User{
   sayHi(){
       let filedName = "Darkcod"
       alert(`Hello,${this.filedName}`) //Hello,undefined
   }
}

 new User().sayHi()

總結:

  1. 面向對象編程最重要的原則之一 - 從外部接口劃份內部接口,這就涉及到屬性和方法的可訪問範圍度
  2. 在面向對象編程中,可經過private、protected、public來對類的屬性和方法進行限制,例如你從你父親那裏繼承了一些屬性,但你父親其餘屬性不像被你繼承到等。
  3. 在JavaScript中,受保護的屬性和方法名以_開頭,私有的屬性和方法名以#開頭
  4. 面向對象編程的一個較大的好處之一是咱們沒必要理解其內部實現,依然能夠很好地去進行編程開發,例如:一個U盤,咱們想要將電腦中的某些文件拷貝到它那裏進行存儲,這時候咱們並不關心U盤的內部是這樣造成的,咱們只知道經過USB口插入便可完成拷貝的工做
相關文章
相關標籤/搜索