Object.create(null) и hasOwnProperty: что вернётся

Что вернёт следующий код?

console.log(Object.create(null).hasOwnProperty('toString'))

Теория и разбор

Метод hasOwnProperty является методом Object.prototype и доступен «обычным» объектам через цепочку прототипов, а не как автоматически созданное собственное свойство каждого объекта.
Объекты, созданные через Object.create(null), имеют null в качестве [[Prototype]], поэтому не наследуют методы Object.prototype, включая hasOwnProperty.

Код из условия:

console.log(Object.create(null).hasOwnProperty('toString'))

Последовательность вычисления (упрощённо, но по смыслу корректно):

  • Выражение Object.create(null) создаёт объект без прототипа ([[Prototype]] = null).
  • Доступ к свойству .hasOwnProperty возвращает undefined, потому что это свойство не найдено ни в самом объекте, ни в прототипе (прототипа нет).
  • Затем выполняется попытка вызвать undefined как функцию: undefined('toString'), что приводит к TypeError ещё до выполнения console.log(...) (аргумент не успевает вычислиться успешно).
'toString' выбран как пример «из прототипа»: у обычного объекта {} он обычно доступен через Object.prototype, но у null-прототипа прототипной цепочки нет.

Почему возникает TypeError

Ошибка появляется не из‑за строки 'toString', а из‑за отсутствия самой функции hasOwnProperty у объекта с null‑прототипом.
Фактически происходит попытка выполнить вызов у значения undefined, что в JavaScript приводит к TypeError: ... is not a function.

Схема прототипов:

Обычный объект:
obj  --->  Object.prototype  --->  null
 |               |
 |               +-- hasOwnProperty()
 +-- (собственные свойства)

Null-прототип:
dict  --->  null
 |
 +-- (только собственные свойства, без методов Object.prototype)

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

Для проверки «собственного» свойства у объекта без прототипа корректно применять Object.hasOwn(obj, prop), так как он работает и с null‑prototype объектами.
Также корректен универсальный классический подход через заимствование метода: Object.prototype.hasOwnProperty.call(obj, prop).

Примеры корректных подходов:

// 1) Современный вариант (предпочтительный)
const obj = Object.create(null);
obj.toString = 123;
console.log(Object.hasOwn(obj, 'toString')); // true

// 2) Классический универсальный вариант
const obj2 = Object.create(null);
console.log(Object.prototype.hasOwnProperty.call(obj2, 'toString')); // false

// 3) Ещё один вариант «взять hasOwnProperty у обычного объекта»
const obj3 = Object.create(null);
console.log(({}).hasOwnProperty.call(obj3, 'toString')); // false

Таблица различий {} и Object.create(null):

Признак{}Object.create(null)
[[Prototype]]Object.prototypenull
Доступен ли obj.hasOwnProperty(...)Да (унаследован)Нет, будет TypeError при вызове
Работает ли Object.hasOwn(obj, 'x')ДаДа
Есть ли унаследованный toStringОбычно да, через прототипНет, прототипной цепочки нет
Встречается рекомендация не вызывать obj.hasOwnProperty(key) напрямую, потому что:
  • у объектов с null‑прототипом метода нет;
  • в данных может существовать собственное свойство hasOwnProperty, которое «затенит» метод и приведёт к ошибкам или неожиданному поведению.
    Поэтому безопаснее использовать Object.hasOwn(obj, key) или Object.prototype.hasOwnProperty.call(obj, key).
  • Итого: выражение Object.create(null).hasOwnProperty('toString') завершится TypeError, потому что у объекта с null‑прототипом нет унаследованного метода hasOwnProperty, а попытка вызвать undefined как функцию приводит к ошибке.