Get to know MDN better
This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2016.
The extends keyword is used in class declarations or class expressions to create a class that is a child of another class.
An expression that evaluates to a constructor function (including a class) or null.
The extends keyword can be used to subclass custom classes as well as built-in objects.
Any constructor that can be called with new and has the prototype property can be the candidate for the parent class. The two conditions must both hold — for example, bound functions and Proxy can be constructed, but they don't have a prototype property, so they cannot be subclassed.
The prototype property of the ParentClass must be an Object or null, but you would rarely worry about this in practice, because a non-object prototype doesn't behave as it should anyway. (It's ignored by the new operator.)
extends sets the prototype for both ChildClass and ChildClass.prototype.
| extends clause absent | Function.prototype | Object.prototype |
| extends null | Function.prototype | null |
| extends ParentClass | ParentClass | ParentClass.prototype |
The right-hand side of extends does not have to be an identifier. You can use any expression that evaluates to a constructor. This is often useful to create mixins. The this value in the extends expression is the this surrounding the class definition, and referring to the class's name is a ReferenceError because the class is not initialized yet. await and yield work as expected in this expression.
While the base class may return anything from its constructor, the derived class must return an object or undefined, or a TypeError will be thrown.
If the parent class constructor returns an object, that object will be used as the this value for the derived class when further initializing class fields. This trick is called "return overriding", which allows a derived class's fields (including private ones) to be defined on unrelated objects.
Warning: The standard committee now holds the position that the built-in subclassing mechanism in previous spec versions is over-engineered and causes non-negligible performance and security impacts. New built-in methods consider less about subclasses, and engine implementers are investigating whether to remove certain subclassing mechanisms. Consider using composition instead of inheritance when enhancing built-ins.
Here are some things you may expect when extending a class:
However, the above expectations take non-trivial efforts to implement properly.
These problems are not unique to built-in classes. For your own classes, you will likely have to make the same decisions. However, for built-in classes, optimizability and security are a much bigger concern. New built-in methods always construct the base class and call as few custom methods as possible. If you want to subclass built-ins while achieving the above expectations, you need to override all methods that have the default behavior baked into them. Any addition of new methods on the base class may also break the semantics of your subclass because they are inherited by default. Therefore, a better way to extend built-ins is to use composition.
extends null was designed to allow easy creation of objects that do not inherit from Object.prototype. However, due to unsettled decisions about whether super() should be called within the constructor, it's not possible to construct such a class in practice using any constructor implementation that doesn't return an object. The TC39 committee is working on re-enabling this feature.
Instead, you need to explicitly return an instance from the constructor.
The first example creates a class called Square from a class called Polygon. This example is extracted from this live demo (source).
Classes cannot extend regular (non-constructible) objects. If you want to inherit from a regular object by making all properties of this object available on inherited instances, you can instead use Object.setPrototypeOf():
This example extends the built-in Date object. This example is extracted from this live demo (source).
All JavaScript objects inherit from Object.prototype by default, so writing extends Object at first glance seems redundant. The only difference from not writing extends at all is that the constructor itself inherits static methods from Object, such as Object.keys(). However, because no Object static method uses the this value, there's still no value in inheriting these static methods.
The Object() constructor special-cases the subclassing scenario. If it's implicitly called via super(), it always initializes a new object with new.target.prototype as its prototype. Any value passed to super() is ignored.
Compare this behavior with a custom wrapper that does not special-case subclassing:
You might want to return Array objects in your derived array class MyArray. The species pattern lets you override default constructors.
For example, when using methods such as Array.prototype.map() that return the default constructor, you want these methods to return a parent Array object, instead of the MyArray object. The Symbol.species symbol lets you do this:
This behavior is implemented by many built-in copying methods. For caveats of this feature, see the subclassing built-ins discussion.
Abstract subclasses or mix-ins are templates for classes. A class can only have a single superclass, so multiple inheritance from tooling classes, for example, is not possible. The functionality must be provided by the superclass.
A function with a superclass as input and a subclass extending that superclass as output can be used to implement mix-ins:
A class that uses these mix-ins can then be written like this:
Inheritance is a very strong coupling relationship in object-oriented programming. It means all behaviors of the base class are inherited by the subclass by default, which may not always be what you want. For example, consider the implementation of a ReadOnlyMap:
It turns out that ReadOnlyMap is not constructible, because the Map() constructor calls the instance's set() method.
We may get around this by using a private flag to indicate whether the instance is being constructed. However, a more significant problem with this design is that it breaks the Liskov substitution principle, which states that a subclass should be substitutable for its superclass. If a function expects a Map object, it should be able to use a ReadOnlyMap object as well, which will break here.
Inheritance often leads to the circle-ellipse problem, because neither type perfectly entails the behavior of the other, although they share a lot of common traits. In general, unless there's a very good reason to use inheritance, it's better to use composition instead. Composition means that a class has a reference to an object of another class, and only uses that object as an implementation detail.
In this case, the ReadOnlyMap class is not a subclass of Map, but it still implements most of the same methods. This means more code duplication, but it also means that the ReadOnlyMap class is not strongly coupled to the Map class, and does not easily break if the Map class is changed, avoiding the semantic issues of built-in subclassing. For example, if the Map class adds a new utility method (such as getOrInsert()) that does not call set(), it would cause the ReadOnlyMap class to no longer be read-only unless the latter is updated accordingly to override getOrInsert() as well. Moreover, ReadOnlyMap objects do not have the set method at all, which is more accurate than throwing an error at runtime.
| ECMAScript® 2027 Language Specification # sec-class-definitions |
Enable JavaScript to view this browser compatibility table.
This page was last modified on Jul 8, 2025 by MDN contributors.
Your blueprint for a better internet.
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license.