Understanding CoffeeScript Class Syntax: Prototype Inheritance and the Role of super()
CoffeeScript’s class syntax compiles to JavaScript constructor functions and prototype assignments, enabling inheritance with extends and super(). Learn how it works, common pitfalls, and how to verify the output.
03 Sept 2025, 07:19 UTC

What You’ll Get
When you write a CoffeeScript class, the compiler turns it into a JavaScript constructor function and attaches methods to its prototype. Inheritance is handled by extends and the super() keyword, which call the parent constructor and allow access to parent methods. This article walks through the transpilation process, shows a concrete example, and highlights common mistakes and limits of the approach.
How CoffeeScript Classes Compile
Below is a minimal CoffeeScript file that demonstrates a base class, a subclass, static methods, and super() usage.
# person.coffee
class Person
constructor: (@name, @age) ->
# instance properties
greet: ->
"Hello, my name is #{@name}"
@species: 'Homo sapiens' # static property
class Employee extends Person
constructor: (@name, @age, @department) ->
super(@name, @age)
@department = @department
work: ->
"Working in #{@department}"
@role: 'Employee' # static property
Running coffee -c person.coffee produces the following JavaScript (simplified for clarity):
// person.js
var Person, Employee;
Person = (function() {
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
return "Hello, my name is " + this.name;
};
Person.species = 'Homo sapiens';
return Person;
})();
Employee = (function(_super) {
__extends(Employee, _super);
function Employee(name, age, department) {
Employee.__super__.constructor.call(this, name, age);
this.department = department;
}
Employee.prototype.work = function() {
return "Working in " + this.department;
};
Employee.role = 'Employee';
return Employee;
})(Person);
function __extends(child, parent) {
for (var key in parent) {
if (Object.prototype.hasOwnProperty.call(parent, key)) child[key] = parent[key];
}
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
}
Key take‑aways from the output:
- The
classkeyword becomes a constructor function. - Instance methods are attached to
prototypeto share a single copy across all instances. - The
__extendshelper sets up the prototype chain and copies static properties. - Calling
super()in the subclass constructor translates toParentClass.__super__.constructor.call(this, …), ensuring the parent constructor runs first. - Static methods/fields are added directly to the constructor function (e.g.,
Person.species).
Verifying Inheritance at Runtime
After transpiling, you can confirm the prototype chain and super() behavior in a browser console or Node REPL.
const emp = new Employee('Alice', 30, 'Engineering');
console.log(emp.greet()); // "Hello, my name is Alice"
console.log(emp.work()); // "Working in Engineering"
console.log(emp instanceof Employee); // true
console.log(emp instanceof Person); // true
console.log(Employee.species); // undefined – static on Person only
console.log(Person.species); // "Homo sapiens"
Notice that Employee inherits Person’s methods and that static properties stay on their respective constructors.
Limitations & Common Pitfalls
Not Native ES6 Classes
Because CoffeeScript classes compile to constructor functions, they lack some ES6 class features:
- They don’t support
Symbol.toStringTagorObject.getPrototypeOfintrospection in the same way native classes do. - Libraries that rely on the
instanceofcheck against a nativeclassmay misbehave if they expect a real ES6 class.
Forgetting to Call super() First
In a subclass constructor, you must call super() before accessing this. Skipping it results in a runtime error similar to:
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
Arrow Functions Inside Classes
Arrow functions capture this lexically. If you define a method with => inside a class, it will not be on the prototype and will bind to the instance that created it. This can lead to memory overhead and unexpected behavior.
Static Methods Misuse
Static members are attached to the constructor, not the prototype. Attempting to call a static method on an instance will fail:
emp.species; // undefined
Person.species; // works
Practical Checklist for Safe Class Usage
- Always call
super()as the first statement in a subclass constructor. - Define instance methods with
->(regular function) unless lexicalthisis required. - Use
@staticProporstatic methodNamefor static members. - After transpiling, run
node -e "require('./person.js'); console.log(new Employee('Bob',25,'HR').work());"to confirm behavior. - When integrating with frameworks that expect native ES6 classes, consider transpiling to ES6 or using
classsyntax in plain JavaScript.
Conclusion
CoffeeScript’s class system is a lightweight wrapper around JavaScript prototype inheritance. Understanding how class, extends, super(), and static members map to JavaScript lets you write efficient, predictable code and avoid common pitfalls. Use the checklist above to ensure your classes behave as intended in both Node and browser environments.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.