# How to use JavaScript Classes

> Learn how to use JavaScript classes introduced in ES6, from defining a constructor and methods to creating objects with new and inheritance using extends.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2018-07-26 | Updated: 2026-09-19 | Topics: [JavaScript](https://flaviocopes.com/tags/js/) | Canonical: https://flaviocopes.com/javascript-classes/

In 2015 the ECMAScript 6 (ES6) standard introduced classes.

[JavaScript](https://flaviocopes.com/javascript/) has a quite uncommon way to implement inheritance: prototypical inheritance. [Prototypal inheritance](https://flaviocopes.com/javascript-prototypal-inheritance/), while in my opinion great, is unlike most other popular programming language's implementation of inheritance,  which is class-based.

People coming from Java or [Python](https://flaviocopes.com/python-introduction/) or other languages had a hard time understanding the intricacies of prototypal inheritance, so the ECMAScript committee decided to sprinkle syntactic sugar on top of prototypical inheritance so that it resembles how class-based inheritance works in other popular implementations.

This is important: JavaScript under the hood is still the same, and you can access an object prototype in the usual way.

## A class definition

This is how a class looks.

```js
class Person {
  constructor(name) {
    this.name = name
  }

  hello() {
    return 'Hello, I am ' + this.name + '.'
  }
}
```

A class has an identifier, which we can use to create new objects using `new ClassIdentifier()`.

When the object is initialized, the `constructor` method is called, with any parameters passed.

A class also has as many methods as it needs. In this case `hello` is a method and can be called on all objects derived from this class:

```js
const flavio = new Person('Flavio')
flavio.hello()
```

## Class inheritance

A class can extend another class, and objects initialized using that class inherit all the methods of both classes.

If the inherited class has a method with the same name as one of the classes higher in the hierarchy, the closest method takes precedence:

```js
class Programmer extends Person {
  hello() {
    return super.hello() + ' I am a programmer.'
  }
}

const flavio = new Programmer('Flavio')
flavio.hello()
```

(the above program prints "_Hello, I am Flavio. I am a programmer._")

Inside a class, you can reference the parent class calling `super()`.

## Class fields

You can declare public fields on the class body. They land on each instance, and you do not have to assign them only inside the constructor:

```js
class Person {
  age = 0

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

const flavio = new Person('Flavio')
flavio.age //0
```

There is still no `protected` keyword in JavaScript. Privacy is handled with `#`, which we cover next.

## Static methods

Normally methods are defined on the instance, not on the class.

Static methods are executed on the class instead:

```js
class Person {
  static genericHello() {
    return 'Hello'
  }
}

Person.genericHello() //Hello
```

You can also declare static fields, and add a `static {}` block for setup code that runs once, when the class is defined.

## Private fields and methods

Private fields and methods use a `#` prefix. They are real language features now, not a naming convention. Code outside the class cannot read or call them:

```js
class Person {
  #name

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

  #greet() {
    return 'Hello, I am ' + this.#name + '.'
  }

  hello() {
    return this.#greet()
  }
}

const flavio = new Person('Flavio')
flavio.hello() //Hello, I am Flavio.
// flavio.#name //SyntaxError
```

You can also mark static members private with `#`:

```js
class Counter {
  static #count = 0

  static next() {
    return ++Counter.#count
  }
}
```

A leading underscore like `_name` is still just a soft convention. It does not hide anything.

## Getters and setters

You can add methods prefixed with `get` or `set` to create a getter and setter, which are two different pieces of code that are executed based on what you are doing: accessing the variable, or modifying its value.

```js
class Person {
  constructor(name) {
    this._name = name
  }

  set name(value) {
    this._name = value
  }

  get name() {
    return this._name
  }
}
```

If you only have a getter, the property cannot be set, and any attempt at doing so (outside of the constructor, which sets the value when you initialize a new object with this class) will be ignored:

```js
class Person {
  constructor(name) {
    this._name = name
  }

  get name() {
    return this._name
  }
}
```

If you only have a setter, you can change the value but not access it from the outside:

```js
class Person {
  constructor(name) {
    this._name = name
  }

  set name(value) {
    this._name = value
  }
}
```

Getters and setters are very useful when you want to execute some code upon changing the property value, or if you want to create a "computed" property. You can alter the values you return by using a getter.

You can also run some code, like logging to the console or to a file when a value is changed.
