← Назад к вопросам

Как запретить добавлять свойства из объекта?

2.0 Middle🔥 171 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы запретить добавление свойств к объекту

В JavaScript существует несколько методов для управления способностью объекта получать новые свойства. Каждый подход имеет разные уровни строгости и применяется в разных сценариях.

1. Object.freeze() - полная заморозка

Object.freeze() делает объект полностью неизменяемым. Невозможно добавлять, удалять или изменять свойства:

const user = {
  name: 'Иван',
  age: 25
};

Object.freeze(user);

// Попытки изменить объект будут игнорированы в нестрогом режиме
user.city = 'Москва'; // Ошибки нет, но свойство не добавится
user.name = 'Пётр'; // Не изменится
delete user.age; // Не удалится

console.log(user); // { name: 'Иван', age: 25 }

// В строгом режиме будет ошибка
'use strict';
user.email = 'test@example.com'; // TypeError: Cannot add property email

Проверка заморозки:

Object.isFrozen(user); // true

2. Object.seal() - запрет на добавление/удаление

Object.seal() позволяет менять существующие свойства, но запрещает добавлять новые или удалять старые:

const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
};

Object.seal(config);

// Можно изменять существующие свойства
config.timeout = 10000; // OK

// Но нельзя добавлять новые
config.retries = 3; // Игнорируется в нестрогом режиме

// И нельзя удалять
delete config.apiUrl; // Игнорируется

console.log(config); // { apiUrl: 'https://api.example.com', timeout: 10000 }

Проверка сделана seal:

Object.isSealed(config); // true

3. Object.preventExtensions() - только для новых свойств

Object.preventExtensions() запрещает добавлять новые свойства, но позволяет менять и удалять существующие:

const person = {
  firstName: 'Анна',
  lastName: 'Смирнова'
};

Object.preventExtensions(person);

// Можно изменять
person.firstName = 'Мария'; // OK

// Можно удалять
delete person.lastName; // OK

// Но нельзя добавлять новые свойства
person.age = 30; // Игнорируется

console.log(person); // { firstName: 'Мария' }

Проверка:

Object.isExtensible(person); // false

4. Object.defineProperty() - контролируемое описание свойств

Это более гибкий способ с помощью дескрипторов свойств:

const obj = {};

Object.defineProperty(obj, 'readonly', {
  value: 'Это значение не изменяется',
  writable: false,      // Нельзя менять
  enumerable: true,     // Видимо в for...in
  configurable: false   // Нельзя переопределять
});

obj.readonly = 'новое значение'; // Игнорируется
console.log(obj.readonly); // 'Это значение не изменяется'

// С методом Object.defineProperties можно определить несколько свойств
Object.defineProperties(obj, {
  prop1: {
    value: 1,
    writable: false
  },
  prop2: {
    value: 2,
    configurable: false
  }
});

5. Использование Getter без Setter

Это практический способ для инкапсуляции:

const module = {
  _data: { count: 0 },
  
  get data() {
    return this._data;
  }
  // Нет setter, поэтому присваивание не работает
};

module.data = { count: 5 }; // Игнорируется
console.log(module.data); // { count: 0 }

6. Прокси (Proxy) - полный контроль

Proxy позволяет перехватить попытку добавления свойств и решить, разрешить или запретить:

const handler = {
  set(target, property, value) {
    if (property in target) {
      target[property] = value; // Позволяем менять существующие
      return true;
    } else {
      console.warn(`Попытка добавить новое свойство: ${property}`);
      return false; // Запрещаем добавлять новые
    }
  }
};

const safeConfig = new Proxy({}, handler);
safeConfig.existingProp = 'test'; // Добавляем первое свойство
safeConfig.existingProp = 'updated'; // OK
safeConfig.newProp = 'value'; // Предупреждение, не добавляется

Сравнение методов

МетодДобавлятьМенятьУдалятьСложность
freeze()НетНетНетНизкая
seal()НетДаНетНизкая
preventExtensions()НетДаДаНизкая
defineProperty()КонтрольКонтрольКонтрольСредняя
Getter/SetterДаКонтрольДаНизкая
ProxyКонтрольКонтрольКонтрольВысокая

Практический пример с Proxy

class ImmutableConfig {
  constructor(config) {
    return new Proxy(config, {
      set: (target, property) => {
        throw new Error(`Нельзя устанавливать ${property}`);
      },
      deleteProperty: (target, property) => {
        throw new Error(`Нельзя удалять ${property}`);
      },
      has: (target, property) => property in target,
      ownKeys: (target) => Object.keys(target)
    });
  }
}

const config = new ImmutableConfig({
  apiUrl: 'https://api.com',
  token: 'secret'
});

config.apiUrl = 'new'; // Error: Нельзя устанавливать apiUrl

Выбор метода

  • freeze() - если объект полностью неизменяем (константы)
  • seal() - если можно менять значения, но не добавлять новые
  • preventExtensions() - если можно удалять, но не добавлять
  • defineProperty() - для точного контроля над каждым свойством
  • Proxy - для сложной логики и изощрённого контроля

Важное замечание

Все эти методы делают объект неизменяемым только на первом уровне. Вложенные объекты остаются изменяемыми:

const nested = Object.freeze({ user: { name: 'Иван' } });
nested.user.name = 'Пётр'; // Это работает!
console.log(nested.user.name); // 'Пётр'

// Для полной неизменяемости нужно заморозить рекурсивно
function deepFreeze(obj) {
  Object.freeze(obj);
  Object.values(obj).forEach(val => {
    if (typeof val === 'object') deepFreeze(val);
  });
  return obj;
}
Как запретить добавлять свойства из объекта? | PrepBro