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

Откуда берутся свойства объекта которые не задаешь

2.2 Middle🔥 141 комментариев
#JavaScript Core

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

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

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

Откуда берутся «лишние» свойства объекта в JavaScript

Когда в JavaScript создается объект и в нем появляются свойства, которые вы явно не задавали, это обычно происходит из-за одного из трех механизмов языка: наследования по прототипу, геттеров/сеттеров или прокси-объектов. Давайте разберем каждый случай подробно.

1. Наследование через прототипную цепочку (Prototype Chain)

Самый частый источник «неожиданных» свойств. В JavaScript почти все объекты имеют внутреннюю ссылку [[Prototype]] (доступную через __proto__ или методы Object.getPrototypeOf()). Когда вы пытаетесь обратиться к свойству объекта, движок сначала ищет его в самом объекте, а если не находит — идет по цепочке прототипов.

// Пример 1: Наследование от встроенного прототипа
const arr = [1, 2, 3];
console.log(arr.map); // ƒ map() { [native code] }
// map не задавался нами, но наследуется от Array.prototype

// Пример 2: Создание своей цепочки
const animal = { eats: true };
const rabbit = { jumps: true };

// Устанавливаем прототип
Object.setPrototypeOf(rabbit, animal);

console.log(rabbit.jumps); // true (собственное свойство)
console.log(rabbit.eats);  // true (унаследовано из animal)

Важные моменты:

  • Унаследованные свойства не отображаются в Object.keys(), но видны в for...in
  • Проверить, собственное ли свойство: obj.hasOwnProperty('key')
  • Прототипом по умолчанию является Object.prototype, откуда берутся toString, valueOf и другие

2. Геттеры (Getters) и Сеттеры (Setters)

Свойства могут быть определены через дескрипторы с функциями-геттерами, которые вычисляют значение динамически при обращении.

const user = {
    firstName: 'Иван',
    lastName: 'Петров',
    
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    },
    
    set fullName(value) {
        [this.firstName, this.lastName] = value.split(' ');
    }
};

console.log(user.fullName); // "Иван Петров"
// fullName не хранится как данные, а вычисляется при чтении

Особенности геттеров:

  • Не имеют соответствующего значения в объекте
  • Нельзя напрямую перезаписать (только через сеттер)
  • Показываются при перечислении свойств
  • Могут быть унаследованы

3. Прокси-объекты (Proxy)

Прокси позволяют перехватывать и переопределять базовые операции над объектами, создавая иллюзию наличия свойств, которых физически нет.

const virtualObject = new Proxy({}, {
    get(target, prop) {
        if (prop === 'virtualProperty') {
            return 'Это значение создано динамически';
        }
        return undefined;
    },
    
    has(target, prop) {
        return ['virtualProperty', 'anotherVirtual'].includes(prop);
    }
});

console.log(virtualObject.virtualProperty); // "Это значение создано динамически"
console.log('virtualProperty' in virtualObject); // true
// Хотя физически свойства в объекте нет!

4. Свойства из стандартных библиотек и окружения

В браузерах и Node.js многие объекты получают дополнительные свойства от среды выполнения:

// В браузере
console.log(window.location); // Не задавали, но есть
console.log(document.body);   // Наследуется из DOM

// В Node.js
console.log(globalThis.process); // Глобальный объект Node.js

Как исследовать происхождение свойств

Для отладки используйте следующие методы:

const obj = { a: 1 };
const child = Object.create(obj);
child.b = 2;

// 1. Проверить собственное свойство
console.log(child.hasOwnProperty('a')); // false
console.log(child.hasOwnProperty('b')); // true

// 2. Получить дескриптор свойства
console.log(Object.getOwnPropertyDescriptor(child, 'b'));
// { value: 2, writable: true, enumerable: true, configurable: true }

// 3. Посмотреть прототипную цепочку
console.log(Object.getPrototypeOf(child) === obj); // true

// 4. Перечислить ВСЕ свойства (включая унаследованные)
for (let key in child) {
    console.log(`${key}: ${child[key]}`);
    // Выведет и 'a', и 'b'
}

Практические выводы

  1. Производительность: Поиск по цепочке прототипов медленнее, чем доступ к собственным свойствам
  2. Безопасность: Проверяйте hasOwnProperty() при итерации, если нужно только собственные свойства
  3. Отладка: Используйте console.dir() для просмотра целой прототипной цепочки
  4. Совместимость: Некоторые свойства добавляются полифилами или библиотеками

Понимание этих механизмов критически важно для эффективной работы с JavaScript, поскольку они лежат в основе ООП в языке, системы классов ES6+ и многих паттернов проектирования. «Волшебные» свойства — не ошибка, а сознательная архитектурная особенность языка, обеспечивающая гибкость и мощь прототипного наследования.

Откуда берутся свойства объекта которые не задаешь | PrepBro