Skip to main content

How to add a method to a class

You add a method to a class by simply writing it in the class body: greet() { ... }, after which it lands on the prototype and becomes available to every instance. Besides the ordinary method, JavaScript gives you static methods, getters and setters, private methods with #, and method fields holding an arrow function, and each variant solves its own problem.

Theory

TL;DR

  • An ordinary method m() {} in the class body lands on Class.prototype and is shared by all instances.
  • A method can also be attached after the declaration: Class.prototype.m = function () {}.
  • static m() {} belongs to the class itself, instances do not see it.
  • get and set provide access that looks like a plain property.
  • #m() {} is a genuinely private method, reachable only from inside the class.
  • An arrow field m = () => {} never loses this, which makes it handy for callbacks.

Quick example

javascript
class User { constructor(name) { this.name = name; } greet() { console.log(`Hi, ${this.name}!`); } } const u = new User("Alice"); u.greet(); // Hi, Alice!

Ordinary method, and adding a method later

An ordinary (public) method is available on every instance of the class:

javascript
class User { constructor(name) { this.name = name; } greet() { console.log(`Hi, ${this.name}!`); } } const u = new User("Alice"); u.greet(); // Hi, Alice!

Such methods are automatically added to User.prototype, which means they are shared by all instances instead of being recreated for every object.

A method can also be put on the class prototype after the declaration, by hand:

javascript
class User { constructor(name) { this.name = name; } } // Adding the method later User.prototype.sayBye = function () { console.log(`${this.name} says: bye!`); }; const u = new User("Alice"); u.sayBye(); // Alice says: bye!

This works because under the hood a class is just a function with a prototype. One detail differs: a manually added method is enumerable, while methods from the class body are not.

Static method

Such a method is called directly on the class, not on an instance:

javascript
class MathUtils { static square(n) { return n * n; } } console.log(MathUtils.square(5)); // 25

Instances (new MathUtils()) have no access to static methods.

Getter and setter

They are used to "disguise" properties as methods and to control access to them:

javascript
class Product { constructor(price) { this._price = price; } get price() { return this._price + " USD"; } set price(value) { if (value < 0) throw new Error("Price cannot be negative"); this._price = value; } } const p = new Product(1000); console.log(p.price); // "1000 USD" p.price = 1500; console.log(p.price); // "1500 USD"

Reading p.price actually calls get price(), and assigning p.price = ... calls set price().

Private methods and arrow method fields

Private methods with a hash are unreachable from outside, only from inside the class:

javascript
class Account { #logBalance() { console.log(`Current balance: ${this.balance}`); } constructor(balance) { this.balance = balance; this.#logBalance(); // can only be called from here } } const acc = new Account(500); // acc.#logBalance(); -> error, this is a private method

If you need a method to keep its this context, declare it as a field holding an arrow function:

javascript
class Button { label = "Click me"; handleClick = () => { console.log(`Clicked: ${this.label}`); }; } const b = new Button(); b.handleClick(); // Clicked: Click me

Such methods do not lose this even when passed around as a callback:

javascript
setTimeout(b.handleClick, 1000); // everything works correctly

The price for that: an arrow field is created separately for every instance and does not live on the prototype.

Summary table

Method kindSyntaxAccessibilityNotes
Ordinarymethod() {}Through an instanceShared by all instances
Staticstatic method() {}Through the class itselfNot visible on instances
Getter / setterget name() {}, set name(v) {}Like a propertyLets you control access
Private#method() {}Only inside the classFull encapsulation
Method field (arrow)method = () => {}Through an instanceDoes not lose this

Common mistakes

  • Putting a comma or a semicolon between methods in the class body: this is not an object literal, no separators are needed there.
  • Making every method an arrow field "so you never think about this": that gives each instance its own copies of the functions and throws away the prototype benefit.
  • Calling a static method on an instance and getting a TypeError.
  • Naming a getter exactly like a field (get price() plus this.price = ... in the constructor): that gives infinite recursion, which is why the example names the field _price.
  • Forgetting that # methods are invisible even in subclasses: class privacy works per class, not along the prototype chain.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.