Viscosity
Review
Part I · JavaScript for engine builders · Day 2

7. Classes, methods and this

A class is a blueprint: every object it makes gets the same properties, in the same order, and shares the same behaviour. Engines love that, and so will Viscosity.

About 16 minutes, including the exercises and quiz
By the end you will be able to
  • Write a class with a constructor and methods, and create instances with new.
  • Predict what this means inside a method, from how the method is called.
  • Explain and fix a lost this when a method is passed as a callback.
  • Explain why objects made by one class tend to share one shape.

Spot the bug

const a = { x: 0, y: 0, vx: 1, vy: 2 };
const b = { x: 5, y: 1, vx: 0, vy: 1 };
const c = { x: 2, y: 7, vX: 3, vy: 0 };

function move(p) {
  p.x = p.x + p.vx;
}
move(c); // c.x becomes NaN

c was typed with vX instead of vx, so c.vx is undefined, and 2 + undefined is NaN (JavaScript’s “not a number”). Nothing warned you. With a thousand particles written by hand, typos like this are certain. And move floats around on its own, separate from the data it works on.

You want a single blueprint that every particle is built from, with the code that works on particles kept right next to it.

Intuition

A class is a cookie cutter. Every cookie pressed out with it has the same outline. Each cookie can still have its own icing: the same properties, with different values.

class, constructor and new

class Particle {
  constructor(x, vx) {
    this.x = x;
    this.vx = vx;
  }
}

const p = new Particle(3, 1);
console.log(p.x, p.vx); // 3 1
console.log(p);
// Particle { x: 3, vx: 1 }

new Particle(3, 1) builds a particle. Step through what it does:

Step throughWhat new does
class Particle {
constructor(x, vx) {
this.x = x;
this.vx = vx;
}
}
const p = new Particle(3, 1);
const q = new Particle(8, -2);
Variables p and q, the this arrow during construction, and the new objectsNAMESNEW OBJECTS
The class is a blueprint. Defining it creates no particles yet.
1/7
Definition

A class is a blueprint for objects of the same kind[1]. Its constructor is the function that sets up each new object. new creates a fresh empty object, runs the constructor with this meaning that object, and returns it. The result is an instance of the class. Every new makes a separate instance, with its own properties.

Methods and this

Functions written inside the class body, next to the constructor, are methods. Here is move, now living with the data:

class Particle {
  constructor(x, vx) {
    this.x = x;
    this.vx = vx;
  }
  move() {
    this.x = this.x + this.vx;
  }
}

const p = new Particle(0, 2);
const q = new Particle(10, -1);
p.move();
q.move();
console.log(p.x, q.x); // 2 9

There’s one move, and two particles. How does move know which one to change? It doesn’t take a parameter. It uses this.

Intuition

this works like the word “me”. The sentence “move me forward” is the same sentence whoever says it, but it moves whoever is speaking. In p.move(), p is speaking.

Step throughthis is whatever is before the dot
class Particle {
// constructor as before
move() {
this.x = this.x + this.vx;
}
}
const p = new Particle(0, 2);
const q = new Particle(10, -1);
p.move();
q.move();
One shared move method above two particle objects, with this pointing at the object the method was called onSHARED BY ALL PARTICLESmove()px: 0vx: 2qx: 10vx: -1
Two instances, each with its own x and vx. The method move is not copied into them: it is stored once, with the class, and both share it.
1/5
Definition

A method is a function stored on an object or a class. Methods written in a class body are stored once, with the class, and shared by every instance[2]. Inside a method, this is the object the method was called on: in p.move(), the object before the dot[3]. It is decided freshly by each call.

Compare that with last chapter. What a function can see is decided by where it is written. What this means is decided by how it is called.

Try itA class of particles
class Particle {
  constructor(x, vx) {
    this.x = x;
    this.vx = vx;
  }
  move() {
    this.x = this.x + this.vx;
  }
}

const ps = [
  new Particle(0, 2),
  new Particle(10, -1),
];
for (let i = 0; i < ps.length; i++) {
  ps[i].move();
}
console.log(ps);
console.log(ps[0] instanceof Particle);
console.log(ps[0].move === ps[1].move);

Losing this

Since this comes from the dot, a method called without a dot has no object to use:

const m = p.move;
m();
// a TypeError: inside move,
// this is undefined

m is the same function, but m() has nothing before a dot, so inside it this is undefined. (Class code always runs in JavaScript’s strict mode, which is what makes it undefined rather than something stranger[1].) The exact error message differs from browser to browser.

This bites most often with callbacks. Passing p.move passes only the function, not p:

function twice(f) {
  f();
  f();
}

twice(p.move);         // TypeError
twice(() => p.move()); // works

The arrow function keeps the dot: when twice calls it, it calls p.move() properly, with p before the dot.

Pitfall

p.move (no parentheses) is just the function. It doesn’t remember p. To hand a method to someone else, wrap it: () => p.move().

Which class made it? instanceof

console.log(p instanceof Particle); // true

const fake = { x: 0, vx: 2 };
console.log(fake instanceof Particle);
// false

fake has exactly the same properties, but it wasn’t made by new Particle, and instanceof can tell.

Definition

a instanceof C is true when the object a was made by the class C (precisely: when the object holding C’s shared methods is in the chain of objects that a borrows methods from[4]). It checks where an object came from, not what it contains.

Under the hood

Every new Particle(...) adds x and then vx, in the same order, through the same constructor. Remember shapes from chapter 3: engines give objects that have the same properties, added in the same order, one shared hidden shape, and then they know where x sits in every one of them without searching[5]. A class is the simplest way to make thousands of objects that share a shape.

That is also good news for Viscosity. An array whose elements all came from new Particle(...) is the ideal candidate for a struct of arrays: every record has the same fields. It’s a strong hint, not a promise, though. Nothing stops code from later writing p.color = 'red' on one particle, so in chapter 97 Viscosity checks whether a shape can change after the objects are made. And in chapter 43, you’ll implement classes, instances and this yourself, inside your own interpreter.

Your turn

ExerciseA 2D vector class

Write a class Vec. new Vec(x, y) stores x and y. The method add(o) returns a new Vec that is the sum of this vector and o, without changing either. The method len() returns the length, Math.sqrt(x * x + y * y).

class Vec {
  constructor(x, y) {
    // your code here
  }
}

const v = new Vec(3, 4);
console.log(v);
Extra practiceA stack class

Write a class Stack. push(v) puts a value on top. pop() removes the top value and returns it (or undefined if the stack is empty). peek() returns the top value without removing it. size() returns how many values it holds. Arrays have a pop() method that removes and returns the last slot, which will help. Part IV’s virtual machine is built around exactly this.

class Stack {
  // your code here
}

const s = new Stack();
s.push(1);
s.push(2);
console.log(s.pop());

What you learned

  • A class is a blueprint. Its constructor sets up each object.
  • new makes an empty object, runs the constructor with this set to it, and returns it: an instance.
  • Methods live in the class body and are shared by all instances.
  • Inside a method, this is the object before the dot in the call. A method called without a dot loses its this, so wrap it: () => p.move().
  • instanceof checks which class made an object.
  • Objects from one constructor tend to share one shape, which helps engines and Viscosity alike.

Next: Map and Set, two built-in classes for looking things up fast.

Check your understanding

0/6
  1. 1.

    What is the first thing new Particle(3, 1) does?

  2. 2.

    What does this print?

    const p = new Particle(0, 1);
    const q = new Particle(0, 5);
    q.move();
    console.log(p.x, q.x);
  3. 3.

    const m = p.move; m(); What happens?

  4. 4.

    const o = { x: 0, vx: 2 }; What is o instanceof Particle?

  5. 5.

    Where does the move method of 1000 Particle instances live?

  6. 6.

    Why do classes help engines like V8 run property access fast?

References

  1. [1] MDN contributors. Classes. MDN Web Docs. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes (checked 2026-10-31)
  2. [2] MDN contributors. Using classes (JavaScript Guide). MDN Web Docs. developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_classes (checked 2026-10-31)
  3. [3] MDN contributors. this. MDN Web Docs. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this (checked 2026-10-31)
  4. [4] MDN contributors. instanceof. MDN Web Docs. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof (checked 2026-10-31)
  5. [5] Mathias Bynens, Benedikt Meurer (2018). JavaScript engine fundamentals: Shapes and Inline Caches. mathiasbynens.be. mathiasbynens.be/notes/shapes-ics (checked 2026-10-31)