---
description: 🚧 under construction
---

# class

[JS](..) ⟩ [value]() ⟩ [object](obj) ⟩ class

{% hint style="success" %}
([declare](../grammar/declare "mention")) [es6](../feature/es6 "mention")

<mark style="color:yellow;">**creates**</mark> a new <mark style="color:purple;">**class**</mark> and gives it a <mark style="color:yellow;">**name**</mark> ([id](../grammar/token/id "mention")).

* <mark style="color:red;">**no**</mark> [**commas**](../grammar/token/punctuator/comma) between class member declarations:exclamation:
* [**private member**](class/member/private) [<mark style="color:yellow;">**identifiers**</mark>](../grammar/token/id) are <mark style="color:yellow;">**prefixed**</mark> with [**hash (#)**](../grammar/token/punctuator/hash).

```javascript
// ⭐️ class definition
class A { 

    // ⭐️ instance members  (# means "private")
    publicProp;                     // this.publicProp = undefined (by default)
    publicMethod() { ... }          // this.publicMethod()
    
    #privateProp;                   // this.#privateProp
    #privateProp2 = 0;
    
    get #privateGetter() { ... }    // this.#privateGetter
    #privateMethod() { ... }        // this.#privateMethod()
    
    // ⭐️ static members
    static staticProp;              // A.staticProp
    
    // ⭐️ if omitted, a default (empty) constructor is created automatically.
    constructor() { ... }
}

// ⭐️ class expression
let B = class { ... }
```
{% endhint %}

{% tabs %}
{% tab title="🧨" %}
{% hint style="warning" %}
:star: <mark style="color:purple;">**class**</mark> <mark style="color:yellow;">**declaration**</mark> is <mark style="color:red;">**not**</mark> [**hoisted**](../scope/hoist/variable/let-const):exclamation:

* :no\_entry: <mark style="color:red;">**cannot**</mark> use a <mark style="color:purple;">**class**</mark> <mark style="color:yellow;">**before**</mark> its <mark style="color:yellow;">**declaration**</mark> :exclamation:(:point\_right: [tdz](../variable/access/tdz "mention"))
{% endhint %}

{% hint style="danger" %}
a <mark style="color:purple;">**class**</mark>'s [<mark style="color:yellow;">**prototype**</mark>](func/prototype) (property) is <mark style="color:red;">**read-only**</mark>:exclamation:
{% endhint %}

{% hint style="danger" %}
⭐️⭐️⭐️  you can change the [prototype](func/prototype "mention") of a <mark style="color:green;">**function**</mark>, but <mark style="color:red;">**not**</mark> that of a <mark style="color:red;">**class**</mark>.

```javascript
// overwrite a function's prototype is OK
func.prototype = {}     // ✅ OK

// overwrite a class's prototype won't work
Class.prototype = {}    // ❌ won't work (ignored silently❗️)
```
{% endhint %}

{% hint style="danger" %}
:no\_entry: <mark style="color:red;">**ReferenceError**</mark>: [<mark style="color:yellow;">**cannot access '...' before initialization**</mark>](../err/ref/cannot-access-before-init).

an error mostly caused by referencing a [let](../variable/declare/let "mention")/ [const](../variable/declare/const "mention")/ [class](class "mention") in its [tdz](../variable/access/tdz "mention"):exclamation:
{% endhint %}

{% hint style="danger" %}
<mark style="color:yellow;">**using**</mark> [typeof](type/name/typeof "mention") on [lexical-declaration](../grammar/declare/lexical-declaration "mention") ([let](../variable/declare/let "mention")/ [const](../variable/declare/const "mention")/ [class](class "mention")) in its [tdz](../variable/access/tdz "mention") will throw a [<mark style="color:red;">**ReferenceError**</mark>](../err/ref/cannot-access-before-init).&#x20;

```javascript
// ⭐ temporal dead zone (start)
// ------------------------------
// typeof aLet;       // ⛔ ReferenceError: Cannot access 'aLet' before initialization
// typeof aConst;     // ⛔ ReferenceError: Cannot access 'aConst' before initialization
// typeof aClass;     // ⛔ ReferenceError: Cannot access 'aClass' before initialization

typeof undeclared;        // ❗ 'undefined'

// ⭐ lexical declarations (let/const/class)
// --------------------------------------------
let aLet;                 // ⭐ initialized to `undefined`
const aConst = "hello";
class aClass {}
```

* replit：[TDZ: let/const/class](https://replit.com/@pegasusroe/TDZ-letconstclass#index.js)
{% endhint %}
{% endtab %}

{% tab title="⭐️" %}
{% hint style="success" %}
What <mark style="color:blue;">class</mark> <mark style="color:orange;">User</mark> <mark style="color:blue;">{...}</mark> does:

* creates a <mark style="color:purple;">**function**</mark> <mark style="color:orange;">User</mark>,  function body taken from <mark style="color:purple;">**constructor()**</mark>.
* stores methods in <mark style="color:orange;">User</mark><mark style="color:purple;">**.prototype**</mark>.
{% endhint %}

{% hint style="warning" %}
⭐️ <mark style="color:purple;">**class**</mark> is <mark style="color:red;">**different**</mark> from a <mark style="color:yellow;">**regular**</mark> [func](func "mention")：

* labelled by a special **internal property** <mark style="color:yellow;">`[[IsClassConstructor]]`</mark>.
* **must** be called with <mark style="color:purple;">**new**</mark>.
* <mark style="color:orange;">**methods**</mark> are <mark style="color:orange;">**non-enumerable**</mark>. (not enumerated in a <mark style="color:purple;">**for...in**</mark> loop)
* **class body code** always <mark style="color:purple;">**use strict**</mark>.
{% endhint %}

{% hint style="danger" %}
⭐️ 注意：<mark style="color:purple;">**class**</mark> 的<mark style="color:orange;">**語法**</mark>與直接寫一個<mark style="color:orange;">**物件**</mark>(**literal** **object**)的方式不同。

```javascript
// ⭐️ property/method/getter/setter 間都要用「逗號」隔開❗️
let user = {

  name   : "John",    // ⭐️ 屬性間用「逗號」隔開
  surname: "Smith",

  set fullName(value) {
    [this.name, this.surname] = value.split(" ");
  },                  // ⭐️ method/getter/setter 間也要用「逗號」隔開

  get fullName() {
    return `${this.name} ${this.surname}`;
  }
};
```
{% endhint %}

{% hint style="warning" %}
<mark style="color:red;">**not**</mark>  [block](../grammar/statement/other/block "mention")：

* [obj](obj/create/obj "mention") / [class](class "mention") / [switch](../grammar/statement/flow/branch/switch "mention") ( <mark style="color:red;">**no**</mark> [block](../grammar/statement/other/block/block "mention"):exclamation:)
* [func](func "mention")'s [scope](../scope/function) is <mark style="color:yellow;">**different**</mark> from a [block](../grammar/statement/other/block/block "mention"):exclamation:

📗 [You Don't Know JS Yet: Scopes & Closrues](https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch6.md#scoping-with-blocks)
{% endhint %}
{% endtab %}

{% tab title="🔴" %}
* <mark style="color:yellow;">**class identity**</mark>
  * [custom-type-name](type/name/custom-type-name "mention") - define custom type name for class.
* :beginner: [<mark style="color:yellow;">**class members**</mark>](class/member)
  * [field](class/member/field "mention")
  * [private](class/member/private "mention")
  * [static](class/member/static "mention")
  * [private-protected-members](class/member/private-protected-members "mention")
  * [getter-setter](class/member/getter-setter "mention")
  * [method](class/member/method "mention")
    * [bound-method](class/member/bound-method "mention")
* :beginner: [<mark style="color:yellow;">**class inheritance**</mark>](class/inheritance)
  * [super](class/inheritance/super "mention")
  * [override-constructor](class/inheritance/override-constructor "mention")
  * [override-methods](class/inheritance/override-methods "mention")
* :beginner: [<mark style="color:yellow;">**class examples**</mark>](class/example)
  * [complex](class/example/complex "mention") - complex numbers.
* other topics
  * [make-iterables](../iteration/iterable/make-iterables "mention")
* <mark style="color:yellow;">**custom functions**</mark>
  * [isclass](type/type-functions/isclass "mention") - check if value is a class.
{% endtab %}

{% tab title="👥" %}
* [prototype](func/prototype "mention") of a class is <mark style="color:orange;">**non-writable**</mark>, <mark style="color:orange;">**non-configurable**</mark>, that is, <mark style="color:red;">**can't reassign**</mark> it, <mark style="color:red;">**can't delete**</mark> it or <mark style="color:red;">**change its**</mark> [<mark style="color:red;">**flags**</mark>](obj/prop/attr).
* [attr](obj/prop/attr "mention") is used in [isclass](type/type-functions/isclass "mention") to distinguish between a [func](func "mention") and a [class](class "mention").
{% endtab %}

{% tab title="💈" %}
* [replit](https://replit.com/@pegasusroe/JS-class-definition#index.js)

#### ⭐️ class definition

```javascript
class User {

    // -------------------------
    //     ⭐️ static members
    // -------------------------
    
    static planet = "Earth";           // static property

    static staticMethod() {            // static method
        return 'static method'
    }
    
    static get age() { return this._age }     // getter

    static set age(value) {                   // setter
        if (value < 0) { return }
        this._age = value
    }

    // -------------------------
    //     ⭐️ class fields
    // -------------------------
    
    age = 0;                        // regular class field
    hobby = prompt('any hobby?');   // ⭐️ function value as property value
    boundMethod = () => { };        // 🔗 bound method (`this` === instance)

    // -------------------------
    //     ⭐️ getters/setters
    // -------------------------
    
    get name() { return this._name }        // getter
    set name(value) { this._name = value }  // setter

    // -----------------
    //     ⭐️ methods
    // -----------------

    constructor() { }                    // ⭐️ constructor
    method() { }                         // regular method
    ['say' + 'Hi']() { log(`hello`) }    // ⭐ computed-name method
}
```

#### ⭐️ class expression

```javascript
// ⭐️ class expression
let User2 = class {
  sayHi() {}
};

// ⭐️ class expression as return value
function returnUserClass(){
    return class {
      sayHi() {}
    };
}
```

#### Notes about [gas](../../appendix/gas "mention")：

```javascript
// • (static/instance) "class fields".
//   ❌ GAS 不支援
//   ✅ 可用 (static/instance) getters/setters 代替.
```

💈範例：

```javascript
let user = new User('Mary');
user.name = 'Joe';                  // ⭐ setter: this._name = 'Joe'
user.sayHi();                       // "hello"

User.age = -9;                      // "age cannot be negative: -9"
User.age = 10;

[
    user.name,           // "Joe"
    user.hobby,
    user.planet,         // undefined

    User.planet,         // "Earth"
    User.staticMethod(), // "static method"

    User.age,            // 10

].forEach(x => log(x));
```
{% endtab %}

{% tab title="📗" %}
* [ ] JS.info ⟩&#x20;
  * [ ] [Classes](https://javascript.info/classes) ⟩ [Class basic syntax](https://javascript.info/class#the-class-syntax)
  * [ ] [Constructor, operator "new"](https://javascript.info/constructor-new)
  * [ ] [Mixins](https://javascript.info/mixins)
* [ ] [javascript-the-definitive-guide](../../master/ref/javascript-the-definitive-guide "mention") ⟩ 5.7.3 class&#x20;
{% endtab %}

{% tab title="📘" %}
* MDN ⟩ [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference) ⟩ [Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
{% endtab %}

{% tab title="🗣" %}
* [How to change Class's Prototype in ES6](https://stackoverflow.com/questions/37680766/how-to-change-classs-prototype-in-es6)
{% endtab %}
{% endtabs %}
