JS: Class Tutorial

By Xah Lee. Date: . Last updated: .

New in ES2015.

To understand class fully, you should first review JavaScript's object system. [see JS: Object System Overview]

Class Declaration Syntax

The syntax for class declaration is:

class class_name { method1 method2 method3 … }

where a method has one of the following form:

Semicolon ; can be used after each method, but is not required.

(Note: class body are all function definitions. You cannot have variable there. Class cannot have property that is not function.)

Example:

// example of a class
class A {

    constructor(x) {
        this.p = x;
        console.log("constructor called with arg " + x)
    }

 ff (x) {console.log("ff called with arg " + x)}

 static ss (x) {console.log("ss called with arg " + x)}

 set p1 (x) {console.log("setter called")}

 get p1 () {console.log("getter called")}

}

// ---------------------------
// using the class

// static method is called directly, not via instance of a object
A.ss(3); // prints: ss called with arg 3

// create a instance.
const x = new A(4); // prints: constructor called with arg 4

console.log(x); // A { p: 4 }

x.ff(1); // prints: ff called with arg 1

x.p1 = 1; // prints: "setter called"

x.p1; // prints: "getter called"

Class Semantics

When a class is defined, for example, this:

class MyClass { contructor (params) {body} method1 method2 static smethod1 }

A magic property key "prototype" is created. The value of MyClass.prototype is a object object, with all the methods defined in MyClass, except static methods. That is, the value of MyClass.prototype is this:

{ constructor: function (params) {body}, method1, method2 }

When new MyClass(args) is called:

  1. A new temporary empty object T is created. Parent of T is MyClass.prototype.
  2. Constructor method is called with arguments args, its this value is T. [see JS: “this” Binding]
  3. If the constructor method has return statement and returns a value of type object, then that object is returned. Else, T is returned.

The end result is a new object, and its parent is MyClass.prototype (provided that the constructor does not return a object itself.).

// The class function defines the prototype object
class C {
    // constructor. called when class is called with new.
    constructor(x) {
        console.log("constructor called with arg " +x);
        this.p = x; // add a property
    }

    ff (x) { console.log("ff called with arg " +x) }

    static ss (x) { console.log("ss called with arg " +x) }

}

// create a object
const cc = new C(3);
// prints: constructor called with arg 3

console.log(cc); // C { p: 3 }

console.log(
Reflect.ownKeys (cc)
) // [ 'p' ]

// show parent
console.log(
Object.getPrototypeOf (cc) === C.prototype
); // true

// show prototype's properties
console.log(
Reflect.ownKeys (C.prototype)
); // [ 'constructor', 'ff' ]

Class Expression

Class can be created by expression form:

Class expression returns a value. Can be called inline.

// class is a expression. it returns a value. can be called inline
console.log (
    new ( class B { constructor(x) { this.p = x; } } ) (3)
); // B { p: 3 }

The name in x = class name {…}; is optional. When given, it allows you to refer to itself inside the class body, but the name is not exposed outsite of it.

// the name of a named class expression is only available inside the class body

const D = class C { constructor(x) { this.p = x; } };

new C(3);
// ReferenceError: C is not defined

Repeated Class Declaration

Class declaration of the same name cannot happen twice. If so, it's an error.

class x {};
class x {}; // SyntaxError: Identifier 'x' has already been declared

No Name Hoisting

Class name is not hoisted (regardless it's defined via declaration or expression). (That means, the name won't be available until the class definition is reached. Unlike function declaration. [see JS: Function Declaration vs Function Expression] )

// class definition does not have name hoisting
// here's a example with class declaration

const a = new A();
// ReferenceError: A is not defined

class A {}
// class definition does not have name hoisting
// here's a example with class expression

const a = new A();
// TypeError: A is not a constructor

const A = class {};

Class Must be Called with 「new」

Class function must be called with keyword new. It cannot be called like a function by itself.

class A {}
A();
// TypeError: Class constructor A cannot be invoked without 'new'

Define Getter/Setter Properties

To define getter/setter properties, just use the get or set keyword in front of the method definition.

[see JS: Getter/Setter Properties]

class A {
    // getter property
    get m() {
        return new Date();
    }
}

const x = new A;

console.log(x.m); // prints current date time

// (getter properties are properties that return value from a function, but with normal acess syntax not function call)

keyword 「static」

Method names can be declared with a static keyword in front. This is called static method.

Static methods becomes a property of the class function object itself.

Static method does not become part of the prototype object. Thus, object created by the class will not inherit static methods.

// static methods are properties of the class function itself
class D {
    static s(x) { console.log("s called"); return x + 1;}
}

console.log(
    D.s(0)
);
 // prints: s called
// 1

// show all property keys
console.log( Reflect.ownKeys (D) ); // [ 'length', 'name', 'prototype', 's'' ]

Static method cannot be called from a instance of the object. (because static method isn't in the prototype object.)

class E { static f (x) { return x + 1;} }

console.log(
    E.prototype.hasOwnProperty ("f")
); // false

const a = new E;

// static method cannot be called from a instance of the object
console.log(
    a.f(4)
);
// TypeError: a.f is not a function

Type of Class is Function

Class declaration syntax is:

class name {…}

Class is a special function object. In many ways, it's same as function.

  1. like function, typeof on class is "function".
  2. like function, parent of class is Function.prototype.
  3. like function, it has properties { length, name, prototype}. (the property name is new in ES2015.)
  4. like function, the value of the property key "prototype", is a new object object with a property key "constructor", by default. [see JS: Property Key "prototype"]
  5. like function, the value of this constructor property, is the class function itself.

However, class function must be called with keyword new. It cannot be called like a function by itself.

// class is a special function object, in many ways, it's same as function

// define a empty class named A
class A {}

console.log( typeof A === "function" ); // true

// parent is Function.prototype
console.log(
    Object.getPrototypeOf (A) === Function.prototype
); // true

// list all properties
console.log( Reflect.ownKeys (A) ); // [ 'length', 'name', 'prototype' ]
// same properties as function would have

// like function, it has a magical property key "prototype"
console.log(
    A.hasOwnProperty ("prototype")
); // true

// like function, the value of this property key "prototype", is a object with property key "constructor"
console.log(
Reflect.ownKeys ( A.prototype )
 );
// [ 'constructor' ]

// the value of the property key "constructor", is A itself
console.log( A.prototype.constructor === A ); // true

Summary of What 「class」 Keyword Do

The class keyword lets you:

  1. Define a “class” MyClass. In the body, it contains a constructor function C, and a group of functions Ms.
  2. Creates a object P that that has Ms as properties. P is the value of MyClass.prototype.
  3. When new MyClass (args) is called, create a new object X, make X's parent to be P, call C(args) with thisBinding to be X. Return X. (if C has return statement and returns a object, then that object is returned instead.)

Note: JavaScript class is not like Java, Python, Ruby's class model. JavaScript's class function is just a convenient function to create objects with specified parent object and methods. No new object model is introduced with the class feature of ES2015. For example, classes in java has a tree structure relationship, and objects created from class mirror that structure. In JavaScript, nothing like that happens. [see JS: Prototype and Inheritance]

What the keyword class can do can also be done with Object.create or more verbosely with keyword new and function.

[see JS: Object.create]

[see JS: Operator “new”]

Liket it? Put $5 at patreon.

Or, Buy JavaScript in Depth

Ask me question on patreon