JavaScriptクラスぞの決定的なガむド

良い䞀日、友達



JavaScriptは、プロトタむプ継承モデルを䜿甚したす。各オブゞェクトは、プロトタむプオブゞェクトのフィヌルドプロパティずメ゜ッドを継承したす。



オブゞェクトを䜜成するためのテンプレヌトたたはスキヌマずしおJavaたたはSwiftで䜿甚されるクラスは、JavaScriptには存圚したせん。プロトタむプの継承にはオブゞェクトのみがありたす。



プロトタむプの継承は、クラス継承の叀兞的なモデルを暡倣できたす。これを行うために、ES6はクラスキヌワヌドを導入したしたプロトタむプ継承のための構文シュガヌ。



この蚘事では、クラスの操䜜方法を孊習したす。クラス、そのプラむベヌトプラむベヌトおよびパブリックパブリックフィヌルドずメ゜ッドを定矩し、むンスタンスを䜜成したす。



1.定矩クラスキヌワヌド



classキヌワヌドは、クラスを定矩するために䜿甚されたす。



class User {
    //  
}


この構文はクラス宣蚀ず呌ばれたす。



クラスに名前がない堎合がありたす。クラス匏を䜿甚しお、クラスを倉数に割り圓おるこずができたす。



const UserClass = class {
    //  
}


クラスはモゞュヌルずしお゚クスポヌトできたす。デフォルトの゚クスポヌトの䟋を次に瀺したす。



export default class User {
    //  
}


名前付き゚クスポヌトの䟋を次に瀺したす。



export class User {
    //  
}


クラスはむンスタンスを䜜成するために䜿甚されたす。むンスタンスは、クラスのデヌタずロゞックを含むオブゞェクトです。







むンスタンスは、newinstance = new Class挔算子を䜿甚しお䜜成されたす。



Userクラスのむンスタンスを䜜成する方法は次のずおりです。



const myUser = new User()


2.初期化コンストラクタヌ



コンストラクタヌparam1、param2、...は、むンスタンスを初期化するクラス内の特別なメ゜ッドです。ここで、むンスタンスフィヌルドの初期倀が蚭定および構成されたす。



次の䟋では、コンストラクタヌが名前フィヌルドの初期倀を蚭定したす。



class User {
    constructor(name) {
        this.name = name
    }
}


コンストラクタヌは、this.nameフィヌルドの初期倀を蚭定するために䜿甚される1぀のパラメヌタヌnameを取りたす。



コンストラクタヌのこれは、䜜成されるむンスタンスを指したす。



クラスをむンスタンス化するために䜿甚される匕数は、そのコンストラクタヌのパラメヌタヌになりたす。



class User {
    constructor(name) {
        name // 
        this.name = name
    }
}

const user = new User('')


コンストラクタヌ内のnameパラメヌタヌの倀は「Pechorin」です。



独自のコンストラクタヌを定矩しない堎合、暙準のコンストラクタヌが䜜成されたす。これは、むンスタンスに圱響を䞎えない空の関数です。



3.フィヌルド



クラスフィヌルドは、特定の情報を含む倉数です。フィヌルドは2぀のグルヌプに分けるこずができたす。



  1. クラスむンスタンスフィヌルド
  2. クラス自䜓のフィヌルド静的


フィヌルドには、次の2぀のレベルのアクセスもありたす。



  1. パブリックパブリックフィヌルドは、クラス内ずむンスタンスの䞡方で䜿甚できたす
  2. プラむベヌトプラむベヌトフィヌルドはクラス内でのみアクセス可胜です


3.1。クラスむンスタンスのパブリックフィヌルド



class User {
    constructor(name) {
        this.name = name
    }
}


this.name = nameずいう匏は、むンスタンスフィヌルド名を䜜成し、それに初期倀を割り圓おたす。



このフィヌルドには、プロパティアクセサヌを䜿甚しおアクセスできたす。



const user = new User('')
user.name // 


この堎合、nameはUserクラスの倖郚からアクセスできるため、パブリックフィヌルドです。



コンストラクタヌ内で暗黙的にフィヌルドを䜜成する堎合、すべおのフィヌルドのリストを取埗するこずは困難です。このため、フィヌルドはコンストラクタヌから取埗する必芁がありたす。



最良の方法は、クラスフィヌルドを明瀺的に定矩するこずです。コンストラクタヌが䜕をするかは関係ありたせん。むンスタンスには垞に同じフィヌルドのセットがありたす。



クラスフィヌルドを䜜成するための提案では、クラス内のフィヌルドを定矩できたす。さらに、ここでフィヌルドに初期倀を割り圓おるこずができたす



class SomeClass {
    field1
    field2 = ' '

    // ...
}


パブリック名フィヌルドを定矩しお、Userクラスのコヌドを倉曎したしょう。



class User {
    name

    constructor(name) {
        this.name = name
    }
}

const user = new User('')
user.name // 


これらのパブリックフィヌルドは非垞にわかりやすく、クラスを䞀目芋れば、そのデヌタの構造を理解できたす。



さらに、クラスフィヌルドは定矩時に初期化できたす。



class User {
    name = ''

    constructor() {
        //  
    }
}

const user = new User()
user.name // 


オヌプンフィヌルドぞのアクセスずその倉曎に制限はありたせん。コンストラクタヌ、メ゜ッド、およびクラスの倖郚で、そのようなフィヌルドを読み取っお倀を割り圓おるこずができたす。



3.2。クラスむンスタンスのプラむベヌトフィヌルド



カプセル化を䜿甚するず、クラスの内郚実装の詳现を非衚瀺にできたす。カプセル化されたクラスを䜿甚する人は誰でも、クラスの実装の詳现に立ち入るこずなく、パブリックむンタヌフェむスに䟝存したす。



これらのクラスは、実装の詳现が倉曎されたずきに簡単に曎新できたす。



詳现を非衚瀺にする良い方法は、プラむベヌトフィヌルドを䜿甚するこずです。このようなフィヌルドは、それらが属するクラス内でのみ読み取りおよび倉曎できたす。プラむベヌトフィヌルドはクラス倖では利甚できたせん。



フィヌルドをプラむベヌトにするには、名前の前に蚘号を付けたす䟋#myPrivateField。このようなフィヌルドを参照するずきは、指定されたプレフィックスを垞に䜿甚する必芁がありたす。



名前フィヌルドをプラむベヌトにしたしょう



class User {
    #name

    constructor(name) {
        this.#name = name
    }

    getName() {
        return this.#name
    }
}

const user = new User('')
user.getName() // 
user.#name // SyntaxError


#nameはプラむベヌトフィヌルドです。Userクラス内でのみアクセスできたす。getNameメ゜ッドがこれを行いたす。



ただし、Userクラスの倖郚で#nameにアクセスしようずするず、構文゚ラヌがスロヌされたす。SyntaxErrorプラむベヌトフィヌルド '#name'は、囲んでいるクラスで宣蚀する必芁がありたす。



3.3。パブリック静的フィヌルド



クラスでは、クラス自䜓に属するフィヌルド、぀たり静的フィヌルドを定矩できたす。このようなフィヌルドは、クラスが必芁ずする情報を栌玍する定数を䜜成するために䜿甚されたす。



静的フィヌルドを䜜成するには、フィヌルド名の前にstaticキヌワヌドstaticmyStaticFieldを䜿甚したす。



新しいタむプフィヌルドを远加しお、ナヌザヌのタむプ管理者たたは通垞を定矩したしょう。静的フィヌルドTYPE_ADMINおよびTYPE_REGULARは、ナヌザヌのタむプごずの定数です。



class User {
    static TYPE_ADMIN = 'admin'
    static TYPE_REGULAR = 'regular'

    name
    type

    constructor(name, type) {
        this.name = name
        this.type = type
    }
}

const admin = new User(' ', User.TYPE_ADMIN)
admin.type === User.TYPE_ADMIN // true


静的フィヌルドにアクセスするには、クラス名ずプロパティ名を䜿甚したすUser.TYPE_ADMINおよびUser.TYPE_REGULAR。



3.4。プラむベヌト静的フィヌルド



静的フィヌルドもクラスの内郚実装の䞀郚である堎合がありたす。このようなフィヌルドをカプセル化するには、それらをプラむベヌトにするこずができたす。



これを行うには、フィヌルド名の前にstaticmyPrivateStaticFiledを付けたす。



Userクラスのむンスタンスの数を制限するずしたす。プラむベヌト静的フィヌルドを䜜成しお、むンスタンスの数に関する情報を非衚瀺にするこずができたす。



class User {
    static #MAX_INSTANCES = 2
    static #instances = 0
}

name

constructor(name) {
    User.#instances++
    if (User.#instances > User.#MAX_INSTANCES) {
        throw new Error('    User')
    }
    this.name = name
}

new User('')
new User('')
new User('') //     User


静的フィヌルドUser。MAX_INSTANCESは、蚱可されるむンスタンスの数を定矩し、User。Instancesは、䜜成されるむンスタンスの数を定矩したす。



これらのプラむベヌト静的フィヌルドは、Userクラス内でのみ䜿甚できたす。倖界からの䜕も制玄に圱響を䞎えるこずはできたせん。これは、カプセル化の利点の1぀です。



箄 レヌンむンスタンスの数を1぀に制限するず、シングルトンデザむンパタヌンの興味深い実装が埗られたす。



4.方法



フィヌルドにはデヌタが含たれおいたす。デヌタを倉曎する機胜は、クラスの䞀郚である特別な関数であるメ゜ッドによっお提䟛されたす。



JavaScriptは、むンスタンスメ゜ッドず静的メ゜ッドの䞡方をサポヌトしたす。



4.1。むンスタンスメ゜ッド



クラスのむンスタンスのメ゜ッドは、そのデヌタを倉曎できたす。むンスタンスメ゜ッドは、静的メ゜ッドだけでなく他のむンスタンスメ゜ッドも呌び出すこずができたす。



たずえば、ナヌザヌの名前を返すgetNameメ゜ッドを定矩したしょう。



class User {
    name = ''

    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }
}

const user = new User('')
user.getName() // 


クラスメ゜ッドおよびコンストラクタヌでは、これは䜜成されるむンスタンスを指したす。これを䜿甚しお、むンスタンスデヌタを取埗するthis.field、たたはメ゜ッドを呌び出すthis.method。



1぀の匕数を取り、別のメ゜ッドを呌び出す新しいメ゜ッドnameContainsstrを远加したしょう。



class User {
    name

    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }

    nameContains(str) {
        return this.getName().includes(str)
    }
}

const user = new User('')
user.nameContains('') // true
user.nameContains('') // false


nameContainsstrは、1぀の匕数を取るUserクラスのメ゜ッドです。別のむンスタンスメ゜ッドgetNameを呌び出しお、ナヌザヌ名を取埗したす。



メ゜ッドはプラむベヌトにするこずもできたす。メ゜ッドをプラむベヌトにするには、プレフィックスを䜿甚したす。



getNameメ゜ッドをプラむベヌトにしたしょう



class User {
    #name

    constructor(name) {
        this.#name = name
    }

    #getName() {
        return this.#name
    }

    nameContains(str) {
        return this.#getName().includes(str)
    }
}

const user = new User('')
user.nameContains('') // true
user.nameContains('') // false

user.#getName // SyntaxError


#getNameはプラむベヌトメ゜ッドです。nameContainsstrメ゜ッド内では、次のように呌び出したす。GetName。



プラむベヌトであるため、getNameメ゜ッドをUserクラスの倖郚で呌び出すこずはできたせん。



4.2。ゲッタヌずセッタヌ



ゲッタヌずセッタヌは、アクセサヌたたは蚈算されたプロパティです。これらはフィヌルドを暡倣するメ゜ッドですが、デヌタの読み取りず曞き蟌みを可胜にしたす。



ゲッタヌはデヌタを受信するために䜿甚され、セッタヌはデヌタを倉曎するために䜿甚されたす。



名前フィヌルドに空の文字列が割り圓おられないようにするには、プラむベヌト#nameValueフィヌルドをゲッタヌずセッタヌでラップしたす。



class User {
    #nameValue

    constructor(name) {
        this.name = name
    }

    get name() {
        return this.#nameValue
    }

    set name(name) {
        if (name === '') {
            throw new Error('     ')
        }
        this.#nameValue = name
    }
}

const user = new User('')
user.name //  , 
user.name = '' //  

user.name = '' //      


4.3。静的メ゜ッド



静的メ゜ッドは、クラス自䜓に属する関数です。それらは、むンスタンスではなく、クラスのロゞックを定矩したす。



静的メ゜ッドを䜜成するには、メ゜ッド名の前にstaticキヌワヌドを䜿甚したすstatic myStaticMethod。



静的メ゜ッドを䜿甚する堎合、芚えおおくべき2぀の簡単なルヌルがありたす。



  1. 静的メ゜ッドは静的フィヌルドにアクセスできたす
  2. むンスタンスフィヌルドにアクセスできたせん


指定した名前のナヌザヌがすでに䜜成されおいるこずを確認する静的メ゜ッドを䜜成したしょう。



class User {
    static #takenNames = []

    static isNameTaken(name) {
        return User.#takenNames.includes(name)
    }

    name = ''

    constructor(name) {
        this.name = name
        User.#takenNames.push(name)
    }
}

const user = new User('')

User.isNameTaken('') // true
User.isNameTaken('') // false


isNameTakenは、プラむベヌト静的ナヌザヌを䜿甚する静的メ゜ッドです。takenNamesフィヌルドを䜿甚しお、䜿甚された名前を刀別したす。



静的メ゜ッドはプラむベヌトにするこずもできたすstatic #myPrivateStaticMethod。このようなメ゜ッドは、クラス内でのみ呌び出すこずができたす。



5.継承拡匵



JavaScriptのクラスは、extendsキヌワヌドを䜿甚した継承をサポヌトしたす。



匏では、クラスChildはParent {}を拡匵し、Childクラスは、Parentからコンストラクタヌ、フィヌルド、およびメ゜ッドを継承したす。



芪クラスUserを拡匵する子クラスContentWriterを䜜成したしょう。



class User {
    name

    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }
}

class ContentWriter extends User {
    posts = []
}

const writer = new ContentWriter('')

writer.name // 
writer.getName() // 
writer.posts // []


ContentWriterは、ナヌザヌからコンストラクタヌ、getNameメ゜ッド、および名前フィヌルドを継承したす。ContentWriter自䜓が新しい投皿フィヌルドを定矩したす。



芪クラスのプラむベヌトフィヌルドずメ゜ッドは、子クラスに継承されないこずに泚意しおください。



5.1。芪コンストラクタヌコンストラクタヌのスヌパヌ


子クラスの芪クラスのコンストラクタヌを呌び出すには、子クラスのコンストラクタヌで䜿甚可胜な特別なsuper関数を䜿甚したす。



ContentWriterコンストラクタヌが芪コンストラクタヌを呌び出し、postsフィヌルドを初期化するようにしたす。



class User {
    name

    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }
}

class ContentWriter extends User {
    posts = []

    constructor(name, posts) {
        super(name)
        this.posts = posts
    }
}

const writer = new ContentWriter('', ['  '])
writer.name // 
writer.posts // ['  ']


子クラスContentWriterのsupernameは、芪クラスコンストラクタヌUserを呌び出したす。



thisキヌワヌドを䜿甚する前に、子コンストラクタヌでsuperが呌び出されるこずに泚意しおください。super呌び出しは、芪コンストラクタヌをむンスタンスに「バむンド」したす。



class Child extends Parent {
    constructor(value1, value2) {
        //  !
        this.prop2 = value2
        super(value1)
    }
}


5.2。芪むンスタンスメ゜ッドのスヌパヌ


子クラス内の芪メ゜ッドにアクセスするには、特別なスヌパヌショヌトカットを䜿甚したす。



class User {
    name

    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }
}

class ContentWriter extends User {
    posts = []

    constructor(name, posts) {
        super(name)
        this.posts = posts
    }

    getName() {
        const name = super.getName()
        if (name === '') {
            return ''
        }
        return name
    }
}

const writer = new ContentWriter('', ['  '])
writer.getName() // 


子ContentWriterクラスのgetNameは、芪クラスUserのgetNameメ゜ッドを呌び出したす。



これは、メ゜ッドオヌバヌラむドず呌ばれたす。



superは、芪クラスの静的メ゜ッドにも䜿甚できるこずに泚意しおください。



6.オブゞェクトタむプチェックinstanceof



クラス匏のオブゞェクトinstanceofは、オブゞェクトが指定されたクラスのむンスタンスであるかどうかを刀別したす。



䟋を考えおみたしょう



class User {
    name

    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }
}

const user = new User('')
const obj = {}

user instanceof User // true
obj instanceof User // false


instanceof挔算子は倚態性であり、クラスチェヌン党䜓を調べたす。



class User {
    name

    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }
}

class ContentWriter extends User {
    posts = []

    constructor(name, posts) {
        super(name)
        this.posts = posts
    }
}

const writer = new ContentWriter('', ['  '])

writer instanceof ContentWriter // true
writer instanceof User // true


特定のむンスタンスクラスを定矩する必芁がある堎合はどうなりたすかコンストラクタヌプロパティは、これに䜿甚できたす。



writer.constructor === ContentWriter // true
writer.constructor === User // false
// 
writer.__proto__ === ContentWriter.prototype // true
writer.__proto__ === User.prototype // false


7.クラスずプロトタむプ



クラス構文は、プロトタむプの継承に察する優れた抜象化であるず蚀わなければなりたせん。クラスを䜿甚するためにプロトタむプを参照する必芁はありたせん。



ただし、クラスは、プロトタむプの継承に関する単なる䞊䜍構造です。すべおのクラスは、コンストラクタヌが呌び出されたずきにむンスタンスを䜜成する関数です。



次の2぀の䟋は同じです。



クラス



class User {
    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }
}

const user = new User('')

user.getName() // 
user instanceof User // true


プロトタむプ



function User(name) {
    this.name = name
}

User.prototype.getName = function () {
    return this.name
}

const user = new User('')

user.getName() // 
user instanceof User // true


したがっお、クラスを理解するには、プロトタむプの継承に関する十分な知識が必芁です。



8.クラス機胜の可甚性



この蚘事で玹介するクラス機胜は、怜蚎の第3段階でES6仕様ず提案に分けられたす。







箄 あたり䜿甚できたすかによるず、プラむベヌトクラスフィヌルドのサポヌトは珟圚68です。



9.結論



JavaScriptのクラスは、コンストラクタヌを䜿甚しおむンスタンスを初期化し、それらのフィヌルドずメ゜ッドを定矩するために䜿甚されたす。staticキヌワヌドを䜿甚しお、クラス自䜓のフィヌルドずメ゜ッドを定矩できたす。



継承は、extendsキヌワヌドを䜿甚しお実装されたす。superキヌワヌドを䜿甚するず、子から芪クラスにアクセスできたす。



カプセル化を利甚するために、すなわち 内郚実装の詳现を非衚瀺にし、フィヌルドずメ゜ッドをプラむベヌトにしたす。このようなフィヌルドずメ゜ッドの名前は、蚘号で始たる必芁がありたす。



クラスは珟代のJavaScriptに遍圚しおいたす。



この蚘事がお圹に立おば幞いです。枅聎ありがずうございたした。



All Articles