Перейти к содержимому

Class Syntax (сахар над прототипами)

В одной фразе: class — синтаксический сахар, который помещает методы на prototype (non-enumerable), создаёт TDZ вместо hoisting и принудительно требует new. На собесе важно объяснить чем именно class отличается от function constructor.

// class vs function constructor — ключевые отличия
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound`; }
}
// Эквивалент вручную:
function AnimalFn(name) { this.name = name; }
AnimalFn.prototype.speak = function () {
return `${this.name} makes a sound`;
};
// Отличия:
// 1. Animal нельзя вызвать без new (TypeError)
// 2. speak из class — non-enumerable (не виден в for...in)
// 3. class в TDZ (не hoisted полностью)
// 4. Тело class всегда в strict mode
// Геттеры, сеттеры, computed methods, Symbol.toPrimitive
class Temperature {
#celsius; // private field
constructor(c) { this.#celsius = c; }
get fahrenheit() { return this.#celsius * 9/5 + 32; }
set fahrenheit(f) { this.#celsius = (f - 32) * 5/9; }
[Symbol.toPrimitive](hint) {
if (hint === 'number') return this.#celsius;
return `${this.#celsius}°C`;
}
}
const t = new Temperature(100);
t.fahrenheit; // 212
t.fahrenheit = 32; // setter: celsius = 0
+t; // 0 (Symbol.toPrimitive)
// Методы на prototype — одна копия; arrow class field — на каждом экземпляре
class Foo {
method() {} // Foo.prototype.method — одна функция
arrowField = () => {} // собственное свойство каждого экземпляра
}
const f1 = new Foo();
const f2 = new Foo();
f1.method === f2.method; // true — одна ссылка
f1.arrowField === f2.arrowField; // false — разные функции
Object.hasOwn(f1, 'method'); // false — на prototype
Object.hasOwn(f1, 'arrowField'); // true — instance property

Итог: Классы делают код читаемым, но не скрывают прототипную природу JS. Под капотом — те же prototype, [[Prototype]], функции-конструкторы.