completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Class basics

Learn JavaScript class syntax, constructors, prototype methods, getters, setters, public fields, function-like class values, and the async factory pattern.

By the end, you can
  • 01
    Write a classWrite a class with fields, a constructor, and methods, and make objects from it with new.
  • 02
    Tell where each part is storedSay which parts each object gets for itself, and which parts all objects share on the prototype.
  • 03
    Use getters, setters, and static methodsAdd a getter and a setter, and use a static async factory when setup must wait for data.

Classes in one picture

A class is a plan for making objects. Every object made from the same class has the same kind of data and the same methods. An object made from a class is called an instance of that class.

In the last lesson, you made objects with a constructor function and new. A class does the same job with shorter, clearer code.

A tiny classPop out in the code editor (opens in a new tab)JavaScript
class User {  constructor(name) {    this.name = name;  }  greet() {    return "Hi " + this.name;  }} const user = new User("Asha");console.log(user.greet());

Here is what each part does:

  • Line 1 starts a class called User.
  • Lines 2 to 4 are the constructor. It runs once for each new object. It stores the name on the new object as this.name.
  • Lines 5 to 7 are a method called greet(). It reads the object's name through this.
  • Line 10 makes one instance with new User("Asha").
  • Line 11 calls greet() and prints Hi Asha.

The name and the method end up in two different places. The name is stored inside user. The method is stored once on User.prototype, a shared object that every User instance links to.

After new User("Asha"). The user cart holds name: "Asha". An arrow named prototype link goes from user to the User.prototype cart, which holds the greet method.new User("Asha")name: "Asha"userits own datalinkUser.prototypegreet()prototypeshared method
new User("Asha") gives user its own name. The greet() method is not inside user; it sits on User.prototype, and user links to it.

Think of a class as a blueprint for a house. Each new builds one house from it.

Real-life analogyBlueprints and houses

A builder reads the blueprint and builds a house. Then the move-in checklist runs once for that house. Each house gets its own furniture. The houses all use one town library, so no house needs its own copy of every book.

In real life: Blueprint
In JavaScript: The class Counter { ... } code
In real life: A new house
In JavaScript: One object made by new Counter()
In real life: Move-in checklist
In JavaScript: The constructor body
In real life: Shared town library
In JavaScript: Methods on Counter.prototype
In real life: Furniture in each house
In JavaScript: Fields and this.value data

This lesson covers these parts of a class:

  • The class code and the constructor.
  • Methods, which all instances share.
  • Static members, which belong to the class itself.
  • Getters, setters, and fields.
  • Classes as values, and a safe way to set up an object that must wait for data.

Later lessons cover classes that extend other classes, private fields, and more.

The class code and the constructor

STEP THROUGH

A class starts with the word class, then a name, then a body in curly braces { }. Inside the body, the method named constructor is special:

  • It runs when you write new ClassName(...).
  • It gets the arguments you pass to new.
  • Inside it, this is the new object being built.

A class can also have fields. A field is a line like history = ["field initialized"]; in the class body. It gives every new object a property with a starting value.

Fields run before the constructor body. The experiment below shows it. The history field makes an array first. Then the constructor body adds a second note to that array.

The order of new Counter(5). Step 1: the history field is made. Step 2: the constructor body stores value 5. Step 3: new gives back the finished counter.new Counter(5)history = [...]this.value = 5counter1. fieldruns first2. constructorbody runs next3. readynew returns it
The field line runs first, so history already exists when the constructor body runs. Then new hands the finished object to counter.
Build one Counter, step by step
Step 0 of 9Ready
Your turn: follow the blue line

A class builds each object in the same order. Step through new Counter and watch the field, then the constructor body, then the method call.

Running in
  1. script
Next: line 2
class Counter {   constructor(start = 0) {    this.value = start;    this.history.push("constructor ran");  }   increment() {    this.value += 1;    return this.value;  }} const counter = new Counter(5);const result = counter.increment();console.log(counter.history.join(" → "));console.log(result);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Change the number passed to the constructor on line 15

Picking a number starts the replay again. The field still runs before the constructor body every time.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Two separate instancesPop out in the code editor (opens in a new tab)JavaScript
class Score {  constructor(player) {    this.player = player;    this.points = 0;  }  addPoint() {    this.points += 1;  }} const first = new Score("Asha");const second = new Score("Ben");first.addPoint();console.log(first.points);console.log(second.points);

The constructor gives each instance its own player and its own points. Line 13 calls addPoint() on first, so only first.points changes. The program prints 1, then 0.

A default value for the constructorPop out in the code editor (opens in a new tab)JavaScript
class Order {  constructor(customer = "Guest") {    this.customer = customer;  }} const order = new Order();console.log(order.customer);

The = "Guest" part is a default value. It is used only when the caller passes nothing. Line 7 calls new Order() with no argument, so customer is Guest. If you passed a name, the object would store that name instead.

A class uses the same prototypes as before

new Counter(5) does the same steps as with a constructor function:

  1. It makes a new, empty object.
  2. It links the object to Counter.prototype.
  3. It runs the setup code with this set to the object.
  4. It gives back the object.

The class version adds safety rules. For example, it stops you from forgetting new.

Methods live on the prototype

INTERACTIVE

When you write a method such as increment() in a class body, JavaScript puts that one function on Counter.prototype. The instances do not get their own copies. They all find the method through their link to the prototype. This is the same sharing you saw in F.prototype & constructors.

The next playground shows a class and a constructor function side by side. Both make objects that greet in the same way. Click the buttons to see where the two are different.

A class next to a constructor function
A class and a constructor functionPop out in the code editor (opens in a new tab)JavaScript
class UserClass {  constructor(name) {    this.name = name;  }  greet() {    return "Hi " + this.name;  }} function UserFunction(name) {  this.name = name;}UserFunction.prototype.greet = function () {  return "Hi " + this.name;}; const classUser = new UserClass("Ada");const functionUser = new UserFunction("Ada");
What happenedClass: greet()
Hi Ada

The class object greets by name: classUser.greet().

Try it yourself

Class: greet() → Hi Ada

A class and a constructor function can make the same objects. The class adds safety rules.
The same user, written two waysPop out in the code editor (opens in a new tab)JavaScript
class UserClass {  constructor(name) {    this.name = name;  }  greet() {    return "Hi " + this.name;  }} function UserFunction(name) {  this.name = name;}UserFunction.prototype.greet = function () {  return "Hi " + this.name;}; const classUser = new UserClass("Ada");const functionUser = new UserFunction("Ada");

To check where a property is stored, use Object.hasOwn(object, "name"). It gives true only when the property sits directly on that object, not on its prototype.

Where the properties are storedPop out in the code editor (opens in a new tab)JavaScript
class User {  role = "reader";   greet() {    return "Hi";  }} const user = new User();console.log(Object.hasOwn(user, "role"));console.log(Object.hasOwn(user, "greet"));console.log(Object.hasOwn(User.prototype, "greet"));

Line 2 is a field, so every User gets its own role. The three checks print:

  • Line 10 prints true: user has its own role.
  • Line 11 prints false: user does not have its own greet.
  • Line 12 prints true: greet is stored on User.prototype.

Object.keys(object) gives an array of the names an object lists as its own. A property that shows up in this list is called enumerable. Class methods are not enumerable, so they don't show up.

Object.keys lists fields, not methodsPop out in the code editor (opens in a new tab)JavaScript
class User {  role = "reader";  greet() {    return "Hi";  }} const user = new User();console.log(Object.keys(user).join(","));console.log(Object.keys(User.prototype).join(",") || "none");

Line 9 prints role, the field. Line 10 prints none: the list for User.prototype is empty, so the || "none" part fills in the word. A for...in loop can also list enumerable properties from the prototype, so use Object.keys when you want only the object's own names.

"Not enumerable" does not mean "private". Any code can still call the method through the prototype, and any code can still read a field. Private fields use a different #name form, which a later lesson covers.

The table sums up the differences. Read each row as a question, then compare the two answers.

How a class differs from a constructor function
What you checkWith a classWith a constructor function
How do you make an object?You write new UserClass("Ada").You write new UserFunction("Ada").
Does Object.keys list the shared methods?No. Class methods are not enumerable.Yes. A method added with = is enumerable.
What if you forget new?It throws a TypeError.Outside strict mode, it runs like a normal function and makes no object.
Is the code in strict mode?Yes, always.Only if the file or function asks for strict mode.
Can you use it above the line that makes it?No. It throws a ReferenceError.Yes. A function declaration works anywhere in its scope.
On each object, on the prototype, or on the class?
  • clicks = 0
  • this.value = start
  • increment() { ... }
  • get fahrenheit() { ... }
  • static async create()
  • typeof Counter
Try it yourself
0 of 6 correct

Sort each line of class code by where it ends up.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Static members belong to the class

CLASS VALUE

A static member is a field or method with the word static in front. It is stored on the class itself, not on the instances. So you call it on the class name: Cart.withTax(), not cart.withTax().

Static members are good for two things:

  • Rules that are the same for every instance, like a tax rate.
  • Named ways to make an instance, which you'll see later in this lesson.
A static field and a static methodPop out in the code editor (opens in a new tab)JavaScript
class Cart {  static taxRate = 0.05;   constructor(total) {    this.total = total;  }   static withTax(total) {    return total * (1 + Cart.taxRate);  }} const cart = new Cart(20);console.log(cart.total);console.log(Cart.withTax(cart.total));

Here is what each part does:

  • Line 2 stores one tax rate, 0.05, on the class Cart.
  • Lines 8 to 10 are a static method. It reads the tax rate and works out a price. It does not need any particular cart.
  • Line 13 makes one cart with its own total of 20.
  • Line 14 prints 20. Line 15 prints 21, which is 20 plus 5 percent tax.
Left: the Cart class holds taxRate and withTax. Cart.withTax(20) works and gives 21. Right: the cart instance holds only total: 20. cart.withTax(20) throws a TypeError.Cart.withTax(20)taxRatewithTax()Cartthe classgives 21cart.withTax(20)total: 20cartone instanceTypeError
taxRate and withTax() are on the class Cart. The object cart only holds its own total, so cart.withTax(20) fails.
Calling a static method on an instance failsPop out in the code editor (opens in a new tab)JavaScript
class Cart {  static withTax(total) {    return total * 1.05;  }} const cart = new Cart();console.log(cart.withTax(20));

The last line throws a TypeError, the error JavaScript gives when you use a value in a way it can't be used. cart is an instance, and it has no withTax method. To fix it, call Cart.withTax(20) on the class.

Static or not? Ask what the method needs

If a method needs one object's data, like this.total, make it a normal method. If it needs only the arguments you pass and rules for the whole class, a static method can be clearer.

Getters, setters, and fields

INTERACTIVE

A getter is a method that you read like a property. You write it with get in front, and you read it without brackets: tea.fahrenheit. Each read runs the method.

A setter is a method that runs when you assign to a property. You write it with set in front, and you use it with =: tea.fahrenheit = 32.

Together they let an object store one number but show it in more than one way. In the playground, the object stores only Celsius. The getter works out Fahrenheit each time you read it.

Read a getter, write a setter
Temperature classPop out in the code editor (opens in a new tab)JavaScript
class Temperature {  constructor(celsius) {    this.celsius = celsius;  }   get fahrenheit() {    return this.celsius * 9 / 5 + 32;  }   set fahrenheit(value) {    this.celsius = (value - 32) * 5 / 9;  }} const tea = new Temperature(100);console.log(tea.fahrenheit);tea.fahrenheit = 32;console.log(tea.celsius);
The object nowTemperature
tea.celsius100
tea.fahrenheit212.0
Try it yourself

The getter reads 100°C as 212.0°F. The setter turns a Fahrenheit number back into Celsius, and stores only Celsius.

The object stores one number, celsius. The getter works out Fahrenheit each time you read it.
A setter can enforce a rulePop out in the code editor (opens in a new tab)JavaScript
class Score {  constructor(value) {    this.value = value;  }   get passed() {    return this.value >= 50;  }   set passed(next) {    this.value = next ? 50 : 0;  }} const score = new Score(42);console.log(score.passed);score.passed = true;console.log(score.value);

Here is what each part does:

  • Lines 6 to 8 are the getter. It turns the stored number into true or false: did the score reach 50?
  • Lines 10 to 12 are the setter. It takes true or false and stores 50 or 0.
  • Line 16 reads score.passed. 42 is less than 50, so it prints false.
  • Line 17 assigns true, so the setter stores 50. Line 18 prints 50.

Fields work differently. Each field becomes a property on each instance. A field can hold a number, an array, or even an arrow function.

An arrow function in a field is handy for a callback, a function you pass to other code to call later, such as a button click. It always uses the instance as this. But each instance gets its own copy of that function.

Field or method?
Fields and a methodPop out in the code editor (opens in a new tab)JavaScript
class ToolbarButton {  clicks = 0;  handleClick = () => {    this.clicks += 1;    return this.clicks;  };   describe() {    return "Button clicked " + this.clicks + " time(s)";  }} const save = new ToolbarButton();const cancel = new ToolbarButton();console.log(save.describe === cancel.describe);console.log(save.handleClick === cancel.handleClick);
Comparisonsreal results
save.describe === cancel.describetrue
save.handleClick === cancel.handleClickfalse
cancel.clicks after one save click0
Try it yourself
worked out when the page loads

A method is stored once on the prototype and shared. An arrow function field is made again for each object.

An arrow function field is handy for a callback, but each object gets its own copy of the function.
Two buttons, save and cancel. Each has an arrow to its own handleClick card, so there are 2 handleClick functions. Both have an arrow to one shared describe card on the prototype.arrow fieldhandleClickhandleClickone per buttonsavecancelmethoddescribe()one, shared
Each button gets its own handleClick, because it is a field. Both buttons share one describe(), because it is a method on the prototype.
Real-life analogyFurniture in each house

Fields are like furniture delivered to each house. Methods are like books in the town library that every house can use. You could put a copy of every book in every house. It would work, but it would take up a lot of room.

In real life: Every house gets its own sofa
In JavaScript: Every instance gets its own fields
In real life: The town library is shared
In JavaScript: Methods on the prototype are shared
In real life: A sofa for every house costs more
In JavaScript: An arrow function field makes one function per instance

Each new instance runs its field lines again. So a field such as items = [] makes a new, empty array for every cart. No two carts share one list by accident.

Each instance gets a new arrayPop out in the code editor (opens in a new tab)JavaScript
class Cart {  items = [];} const first = new Cart();const second = new Cart();first.items.push("tea");console.log(first.items.length);console.log(second.items.length);

Line 7 adds "tea" to first's array only. The program prints 1, then 0. The two carts have two separate arrays.

Use an arrow function field when a callback really needs to keep the instance as this. Otherwise, a normal method is the better choice, because all instances share one copy.

Classes are functions, and waiting setup uses a factory

INTERACTIVE

A class is a value, like a number or a function. In fact, typeof Counter gives "function". (typeof tells you what kind of value something is.) So you can do these things with a class:

  • Store it in a variable.
  • Export it from a file.
  • Pass it to another function.

But a class has one rule a normal function doesn't: you can't call it as Counter(). You must use new Counter().

A class stored in a variablePop out in the code editor (opens in a new tab)JavaScript
const Guest = class {  constructor(name) {    this.name = name;  }   greeting() {    return "Hello, " + this.name;  }}; const guest = new Guest("Asha");console.log(guest.greeting());console.log(typeof Guest);

This code is a class expression: a class with no name of its own, stored in the variable Guest. After line 9, it works like any other class. Line 12 prints Hello, Asha. Line 13 prints function.

Three errors to recognize
  • Calling a class without new throws a TypeError.
  • Using a class name above the line that makes the class throws a ReferenceError, the error for a name you can't use yet. This time before the line runs is called the temporal dead zone.
  • Code in a class always runs in strict mode, JavaScript's safer rule set. So if you copy a method out of its object and call it alone, this is undefined. Reading this.name then throws an error.

A class expression is handy when you need a class in only one place, or want to pick one of two classes, or pass a class into a function. It follows the same rules as any class.

Now for objects that must wait for data before they are ready. new Profile() always gives back the object right away, so a constructor can't wait. Instead, use a static async factory:

  • A factory is a function that makes and returns an object.
  • Static means it is stored on the class, like Profile.create().
  • Async means it can wait, using await, before it returns.

The factory waits for the data. Then it calls the normal constructor and returns the ready object. Anyone reading await Profile.create(...) can see that the code waits.

Static async factory
A factory that waitsPop out in the code editor (opens in a new tab)JavaScript
class Profile {  constructor(name, avatar) {    this.name = name;    this.avatar = avatar;  }   static async create(name) {    const avatar = await loadAvatar(name);    return new Profile(name, avatar);  }} async function loadAvatar(name) {  return name.slice(0, 1).toUpperCase() + "-avatar";} async function main() {  const profile = await Profile.create("Ada");  console.log(profile.avatar);} main();
What the factory madeon click

Not run yet

Try it yourself

Not run yet

A timer makes a short pretend wait, so you can see the pattern now. Later lessons explain how async code and await work.
Coming later: async and await

The words async and await get their own lessons later in the course. For now, remember the pattern: static async create() waits, then returns new ClassName(...).

Where you’ll use this

A class helps when you have many objects that do the same things, but each one keeps its own data. Some examples:

  • Buttons, menus, and other parts of a page.
  • Shopping carts, users, and orders.
  • Players and enemies in a game.
  • Code that checks form input, or code that talks to a server.

A class also keeps the parts easy to find:

  • The constructor takes the data the object needs.
  • Methods do the actions.
  • Getters work out values from the stored data.
  • Static factories give you named ways to make an object.
What a real shopping cart class might hold

A ShoppingCart class might keep its own items field. It might share add() and total() methods on the prototype, and have a getter, get count(). If it must load a saved cart first, it might have static async fromSavedCart(userId).

A small cart classPop out in the code editor (opens in a new tab)JavaScript
class ShoppingCart {  items = [];   add(item) {    this.items.push(item);  }   get count() {    return this.items.length;  }} const cart = new ShoppingCart();cart.add("tea");cart.add("bread");console.log(cart.count);

Each cart keeps its own items list. All carts share one add() method. The count getter works out how many items there are. After two calls to add(), line 16 prints 2.

If your program has only one cart, a plain object may be simpler. A class is worth it when you need many carts that behave the same way.

Pick a class when an object has a clear life: it is made, it changes over time, and several actions belong to it. The constructor can refuse missing data. Methods can keep the data correct. A getter can show a useful value without letting other code change the data directly.

Pick a factory function, a plain function that builds and returns an object, when you only need to turn some input into an object once. Not every object needs a class.

Watch out when you send class objects to a server. JSON.stringify(object) turns an object into text. It keeps only the object's own data, not methods from the prototype. When the data comes back, rebuild the object with new or a factory to get the methods back.

JSON keeps the data, not the methodsPop out in the code editor (opens in a new tab)JavaScript
class User {  constructor(name) {    this.name = name;  }  greet() {    return "Hi " + this.name;  }} const user = new User("Asha");console.log(JSON.stringify(user));console.log(typeof user.greet);

Line 11 prints {"name":"Asha"}, because name is the object's own data. Line 12 prints function, so greet still works. But greet is not in the JSON text, because it is stored on the prototype.

You never have to use classes. Plain objects and factory functions are fine too. Pick a class when new makes it clear that many objects share one set of methods.

Common misconceptions

“Classes replace prototypes.”

No. Classes use prototypes. Methods, getters, and setters are still stored on ClassName.prototype.

“The constructor makes the methods for each object.”

No. The constructor sets up each object's data. Methods are written once and shared by all instances.

“Fields and methods are the same thing.”

No. Each instance gets its own fields. Methods sit on the prototype, unless you put a function in a field on purpose.

“Getters store data.”

No. A getter runs code each time you read it. It can work out a value from stored data without storing anything itself.

“Constructors can wait for data.”

No. A constructor gives back the new object right away. When setup must wait, use a static async factory.

“You can use a class above the line that makes it.”

No. That works for function declarations, but not for classes. Until the class line runs, the class name is in the temporal dead zone, and using it throws a ReferenceError.

“Static methods can read an instance's data.”

No. When you call a static method on the class, this is the class, not an instance. Pass in the data it needs, or use a normal method.

“A getter is a stored field.”

No. A getter is stored on the prototype and runs again on every read. Use a field when you need a value you can store and change.

“A class expression is a different kind of class.”

No. It follows the same rules. The only difference is that it is written as a value and stored in a variable.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upWrite a class

Type the class from the starter code. Then guess the two lines it prints.

Starter codePop out in the code editor (opens in a new tab)JavaScript
class TodoItem {
  constructor(text) {
    this.text = text;
    this.done = false;
  }
  complete() {
    this.done = true;
    return this.text + " done";
  }
}
const task = new TodoItem("Ship lesson");
console.log(task.complete());
console.log(task.done);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeGuess what the two objects share

    Guess both true or false values without running the program.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    class Counter {
      count = 0;
      increment() {
        this.count += 1;
        return this.count;
      }
    }
    const a = new Counter();
    const b = new Counter();
    console.log(a.increment === b.increment);
    console.log(a.count === b.count);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFix a class called without new

      This code throws an error. Fix the line that makes the widget, so the program prints its name.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      class Widget {
        constructor(name) {
          this.name = name;
        }
      }
      const widget = Widget("Panel");
      console.log(widget.name);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeAdd a getter

        Add a getter that turns Celsius into Fahrenheit.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        class Temperature {
          constructor(celsius) {
            this.celsius = celsius;
          }
          get fahrenheit() {
            return this.celsius * 9 / 5 + 32;
          }
        }
        const room = new Temperature(20);
        console.log(room.fahrenheit);

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeUse a static async factory

          Use a static async factory to make a ready profile. Then print its avatar.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          class Profile {
            constructor(name, avatar) {
              this.name = name;
              this.avatar = avatar;
            }
            static async create(name) {
              const avatar = name.slice(0, 1).toUpperCase() + "-avatar";
              return new Profile(name, avatar);
            }
          }
          Profile.create("Ada").then(profile => console.log(profile.avatar));

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            8 QUESTIONS
            Lesson quiz · 8 questionsScore: first tries count
            1. Question 1 of 8What is a JavaScript class?

              Choose an answer to see the explanation.

            2. Question 2 of 8What does this code print? (It checks if two objects share a method.)

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              class Counter {
                value = 0;
                increment() {
                  this.value += 1;
                  return this.value;
                }
              }
              const a = new Counter();
              const b = new Counter();
              console.log(a.increment === b.increment);

              Choose an answer to see the explanation.

            3. Question 3 of 8In a class that doesn't extend another class, what runs before the constructor body?

              Choose an answer to see the explanation.

            4. Question 4 of 8What does this getter code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              class Temperature {
                constructor(celsius) { this.celsius = celsius; }
                get fahrenheit() { return this.celsius * 9 / 5 + 32; }
              }
              console.log(new Temperature(0).fahrenheit);

              Choose an answer to see the explanation.

            5. Question 5 of 8Which statement about classes is true?

              Choose an answer to see the explanation.

            6. Question 6 of 8Why use static async create()?

              Choose an answer to see the explanation.

            7. Question 7 of 8What does this code with static members print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              class Cart {
                static taxRate = 0.05;
                static withTax(total) {
                  return total * (1 + Cart.taxRate);
                }
              }
              console.log(Cart.withTax(20));

              Choose an answer to see the explanation.

            8. Question 8 of 8What does this code print? (It compares two arrow function fields.)

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              class Button {
                click = () => "clicked";
                describe() { return "button"; }
              }
              const one = new Button();
              const two = new Button();
              console.log(one.click === two.click);

              Choose an answer to see the explanation.

            Key takeaways

            • A class is a plan for making objects that share the same methods.
            • The constructor runs once for each new. Fields run just before the constructor body.
            • Methods, getters, and setters are stored once, on the prototype. Fields are stored on each instance.
            • Static members are stored on the class itself, so you call them on the class name.
            • A class is a function value, but you must call it with new, and only after the line that makes it.
            • Use static async create() when setup must wait before the object is ready.

            Remember the one-liner.
            A class is a blueprint: its constructor sets up each new object, and its methods are shared by all of them.

            Up next: Inheritance with extends & super.

            CompleteFrontend Clear concepts. Working examples.