← Назад к вопросам
Как динамически создать класс в runtime?
1.6 Junior🔥 101 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как динамически создать класс в runtime
Это продвинутая техника в JavaScript. Классы — это синтаксический сахар над функциями-конструкторами, и их можно создавать динамически несколькими способами.
1. Динамическое создание через Function конструктор
// Способ 1: Function конструктор
const DynamicClass = new Function(
'name',
`
this.name = name;
this.greet = function() {
return 'Hello, ' + this.name;
}
`
);
const user = new DynamicClass('Alice');
console.log(user.name); // 'Alice'
console.log(user.greet()); // 'Hello, Alice'
Проблемы:
- Очень небезопасно (eval-подобно)
- Плохо читается
- Нет типизации в TypeScript
- Slow по производительности
Когда использовать: Практически никогда. Есть лучшие способы.
2. Factory функция — безопаснее и проще
// Создание класса-фабрики
function createUserClass(defaultRole = 'user') {
class User {
constructor(name, email) {
this.name = name;
this.email = email;
this.role = defaultRole;
}
greet() {
return `Hello, I am ${this.name}`;
}
getInfo() {
return `${this.name} (${this.role})`;
}
}
return User;
}
const AdminUser = createUserClass('admin');
const RegularUser = createUserClass('user');
const admin = new AdminUser('Alice', 'alice@example.com');
const regular = new RegularUser('Bob', 'bob@example.com');
console.log(admin.getInfo()); // 'Alice (admin)'
console.log(regular.getInfo()); // 'Bob (user)'
Плюсы:
- Безопасно
- Читаемо
- Работает с TypeScript
- Гибко
Это лучший способ в 99% случаев.
3. Метапрограммирование через Proxy
// Создание класса с динамическим поведением
const DynamicClass = new Proxy(
class {},
{
construct(target, args) {
// Динамически создаём объект во время создания экземпляра
const [name, age] = args;
return {
name,
age,
greet() {
return `Hello, ${this.name}`;
}
};
}
}
);
const user = new DynamicClass('Alice', 30);
console.log(user.greet()); // 'Hello, Alice'
Когда использовать: Когда нужно перехватить создание экземпляра и изменить его поведение.
4. Динамическое добавление методов
function createClass(methodNames) {
class DynamicClass {
constructor(data) {
this.data = data;
}
}
// Добавляем методы динамически
methodNames.forEach(methodName => {
DynamicClass.prototype[methodName] = function() {
return `Executing ${methodName} on ${this.data}`;
};
});
return DynamicClass;
}
const MyClass = createClass(['run', 'walk', 'jump']);
const instance = new MyClass('rabbit');
console.log(instance.run()); // 'Executing run on rabbit'
console.log(instance.walk()); // 'Executing walk on rabbit'
console.log(instance.jump()); // 'Executing jump on rabbit'
5. Создание класса с наследованием
function createDerivedClass(ParentClass, additionalMethods) {
class DynamicChild extends ParentClass {
constructor(...args) {
super(...args);
this.dynamicProp = 'dynamic';
}
}
// Добавляем методы
Object.entries(additionalMethods).forEach(([name, method]) => {
DynamicChild.prototype[name] = method;
});
return DynamicChild;
}
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return 'Some sound';
}
}
const Dog = createDerivedClass(Animal, {
bark() {
return `${this.name} barks: woof!`;
},
wag() {
return `${this.name} wags tail`;
}
});
const dog = new Dog('Buddy');
console.log(dog.speak()); // 'Some sound'
console.log(dog.bark()); // 'Buddy barks: woof!'
console.log(dog.wag()); // 'Buddy wags tail'
6. Практический пример: регистр компонентов
// Создание динамических компонентов на базе конфигурации
function createComponentFactory(config) {
class DynamicComponent {
constructor(props = {}) {
this.props = props;
this.state = config.initialState || {};
}
render() {
return config.render(this.props, this.state);
}
setState(newState) {
this.state = { ...this.state, ...newState };
}
}
// Добавляем методы жизненного цикла
if (config.onMount) {
DynamicComponent.prototype.onMount = config.onMount;
}
if (config.onDestroy) {
DynamicComponent.prototype.onDestroy = config.onDestroy;
}
return DynamicComponent;
}
const ButtonComponent = createComponentFactory({
initialState: { clicks: 0 },
render(props, state) {
return `<button>${props.label} (${state.clicks})</button>`;
},
onMount() {
console.log('Button mounted');
}
});
const btn = new ButtonComponent({ label: 'Click me' });
console.log(btn.render()); // '<button>Click me (0)</button>'
btn.setState({ clicks: 1 });
console.log(btn.render()); // '<button>Click me (1)</button>'
7. С использованием eval (НЕ РЕКОМЕНДУЕТСЯ!)
// ОПАСНО! Только для демонстрации
function createClassWithEval(className, methodCode) {
const code = `
class ${className} {
${methodCode}
}
`;
eval(code);
return eval(className);
}
// НЕ ДЕЛАЙ ТАК! eval очень небезопасен
8. Практический пример: ORM-подобный паттерн
function createModel(config) {
class Model {
constructor(data) {
Object.assign(this, data);
}
save() {
return { ...this, saved: true };
}
validate() {
return config.validators.every(v => v(this));
}
static find(query) {
// Имитация поиска
return `Found ${JSON.stringify(query)}`;
}
}
// Добавляем валидаторы
config.validators = config.validators || [];
return Model;
}
const User = createModel({
validators: [
(user) => typeof user.name === 'string',
(user) => typeof user.email === 'string'
]
});
const user = new User({ name: 'Alice', email: 'alice@example.com' });
console.log(user.validate()); // true
console.log(user.save()); // { name: 'Alice', email: '...', saved: true }
console.log(User.find({ role: 'admin' })); // 'Found {...}'
Сравнение подходов
| Способ | Безопасность | Производительность | Читаемость | Когда использовать |
|---|---|---|---|---|
| Function конструктор | Низкая | Медленно | Плохая | Почти никогда |
| Factory функция | Высокая | Быстро | Отличная | В 99% случаев |
| Proxy | Средняя | Быстро | Средняя | Перехват поведения |
| Динамические методы | Высокая | Быстро | Хорошая | Когда методы конфигурируемы |
| eval | ОЧЕНЬ низкая | Медленно | Ужасная | НИКОГДА |
TypeScript версия
function createUserClass<T extends Record<string, any>>(
defaultProps: T
): new (name: string) => { name: string } & T {
class User {
name: string;
constructor(name: string) {
this.name = name;
Object.assign(this, defaultProps);
}
}
return User as any;
}
const User = createUserClass({ role: 'user' });
const user = new User('Alice');
Ключевой вывод
Для динамического создания класса в runtime используй:
-
Factory функция (лучший выбор в 99% случаев)
function createClass(...args) { class DynamicClass { ... } return DynamicClass; } -
Proxy (когда нужно перехватить поведение)
-
Динамическое добавление методов (когда методы конфигурируемы)
Избегай Function конструктора и eval — они небезопасны и медленны. Factory функции — это современный, читаемый и безопасный способ.