Mixins (композиция)
В одной фразе: миксины — паттерн горизонтального переиспользования поведения, обходящий ограничение одиночного наследования в JS. На собесе ждут несколько реализаций (Object.assign vs subclass factory), знание проблемы diamond problem и понимание порядка применения.
// Mixin через Object.assign: простой, но методы становятся enumerableconst Serializable = { serialize() { return JSON.stringify(this); }, deserialize(s) { return Object.assign(Object.create(this), JSON.parse(s)); }};const Validatable = { validate() { return Object.values(this).every(v => v !== null); }};
class User { constructor(name, email) { this.name = name; this.email = email; }}Object.assign(User.prototype, Serializable, Validatable);
const u = new User('Alice', 'a@b.com');u.validate(); // trueu.serialize(); // '{"name":"Alice","email":"a@b.com"}'// Subclass factory mixin — поддерживает super, private, правильную цепочкуconst Timestamped = (Base) => class extends Base { constructor(...args) { super(...args); this.createdAt = new Date(); }};
const Tagged = (Base) => class extends Base { #tags = new Set(); addTag(t) { this.#tags.add(t); return this; } hasTag(t) { return this.#tags.has(t); } getTags() { return [...this.#tags]; }};
class Article { constructor(title) { this.title = title; } }
const TimestampedTaggedArticle = Timestamped(Tagged(Article));const post = new TimestampedTaggedArticle('Hello World');post.addTag('js').addTag('ts');post.getTags(); // ['js', 'ts']post.createdAt; // Date объект// Diamond problem: порядок миксинов определяет, чей метод "победит"const A = (Base) => class extends Base { greet() { return 'A'; } };const B = (Base) => class extends Base { greet() { return 'B'; } };
class C extends A(B(Object)) {}// Цепочка: C → anon(A) → anon(B) → Objectnew C().greet(); // 'A' — A применён последним (внешний слой), идёт первым в цепочке
// Если нужен B:class D extends B(A(Object)) {}new D().greet(); // 'B'Итог: Subclass factory mixins предпочтительнее Object.assign — они поддерживают super, private поля и правильную instanceof-цепочку.