Прототипы JS: что выведет object.property после изменений

Дан код:

const object = {};
object.constructor.prototype.property = 1;
object.constructor.prototype = null;
console.log(object.property); 

Какое значение выведет console.log ?

Разбор по шагам

Дан код:

const object = {};
object.constructor.prototype.property = 1;
object.constructor.prototype = null;
console.log(object.property);
  1. После const object = {}; создаётся обычный объект.
    У такого объекта внутренний прототип (внутренний слот) [[Prototype]] указывает на Object.prototype (стандартный прототип для объектных литералов).
  2. Выражение object.constructor обычно не является собственным свойством object.
    Оно находится через прототип: берётся constructor из Object.prototype, и результатом становится функция-конструктор Object.
  3. Строка object.constructor.prototype.property = 1; означает:
  • берётся функция Object,
  • у неё берётся свойство prototype (это и есть объект Object.prototype на данный момент),
  • в этот объект добавляется новое свойство property со значением 1.

Итог: в Object.prototype появляется property, доступное через наследование многим объектам.

  1. Строка object.constructor.prototype = null; переопределяет свойство prototype у функции Object.
    Это меняет «указатель» Object.prototype (как свойство функции Object), но не переподключает прототип у уже созданных объектов.
  2. Вызов console.log(object.property) запускает поиск свойства property:
  • в собственных свойствах object его нет,
  • затем поиск идёт в object.[[Prototype]], который всё ещё указывает на старый объект Object.prototype (в который ранее было добавлено property = 1),
  • поэтому находится значение 1 и оно выводится.
Переопределение Object.prototype и добавление свойств в Object.prototype является потенциально опасной практикой: такие изменения влияют на большое количество объектов и могут приводить к трудноотлавливаемым ошибкам.

Наглядная схема того, что происходит:

Шаг 1:
object
  [[Prototype]] ---> Object.prototype (старый объект-прототип)

Шаг 3:
Object.prototype.property = 1

Шаг 4:
Object.prototype (как свойство функции Object) = null
НО:
object.[[Prototype]] по-прежнему ---> старый Object.prototype, где property = 1

Теория: prototype и [[Prototype]]

В JavaScript важно различать две похожие по названию, но разные сущности.

  1. obj.[[Prototype]] (внутренний прототип объекта)
  • Это «скрытая ссылка» конкретного объекта на другой объект.
  • Именно по этой ссылке движок JavaScript строит цепочку прототипов при поиске свойств: obj.prop.
  1. F.prototype (свойство prototype у функции)
  • Это обычное свойство функции (функция в JavaScript тоже объект).
  • Оно используется оператором new при создании новых объектов: новый объект получает [[Prototype]], равный текущему значению F.prototype.

Ключевой смысл задачи:

  • Добавление property в текущий объект Object.prototype влияет на доступность object.property, потому что object уже наследуется от этого объекта-прототипа.
  • Присваивание Object.prototype = null (то есть object.constructor.prototype = null) влияет на то, что будет считаться prototype у функции Object после этой строки, но не перепривязывает [[Prototype]] уже созданного object.

Как работает чтение object.property:

  • Проверяются собственные свойства object.
  • Если не найдено — проверяется object.[[Prototype]].
  • Далее — object.[[Prototype]].[[Prototype]] и так далее, пока не встретится null.
  • Если цепочка закончилась (дошли до null) и свойство не найдено — результатом будет undefined.

В данной задаче цепочка не заканчивается на null до нахождения property, потому что property лежит в старом объекте-прототипе.

Свойство constructor не является «магической командой», оно тоже ищется по цепочке прототипов как обычное свойство, если не задано напрямую в объекте.

Таблица и примеры

Таблица влияния строк кода:

СтрокаЧто меняетсяВлияние на object.property
object.constructor.prototype.property = 1;Мутируется объект-прототип (в него добавляется property)Да, потому что object наследуется от этого прототипа
object.constructor.prototype = null;Меняется значение prototype у функции ObjectНет, уже созданный object продолжает ссылаться на старый [[Prototype]]

Пример, показывающий разницу между «изменить объект-прототип» и «заменить ссылку на prototype»:

function A() {}
const x = new A();

A.prototype.p = 10;   // изменение существующего прототип-объекта
console.log(x.p);     // 10

A.prototype = { p: 20 }; // замена ссылки на новый объект
console.log(x.p);        // всё ещё 10, потому что x.[[Prototype]] не поменялся

const y = new A();
console.log(y.p);        // 20, потому что y создан после замены A.prototype

Пример, иллюстрирующий, что constructor обычно берётся из прототипа:

const o = {};
console.log(o.hasOwnProperty('constructor')); // false (в большинстве случаев)
console.log(typeof o.constructor);            // function

Кратко: сначала property = 1 добавляется в старый Object.prototype, от которого уже наследуется object, а затем Object.prototype (как свойство функции Object) переопределяется на null без изменения [[Prototype]] уже созданного объекта; поэтому console.log(object.property) выводит 1.