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

У всех ли сущностей есть __proto__

2.2 Middle🔥 202 комментариев
#JavaScript Core#Архитектура и паттерны

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

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

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

Развернутый ответ: __proto__ и современный JavaScript

Краткий ответ

Нет, не у всех сущностей в JavaScript есть __proto__. __proto__ существует только у объектов, созданных с помощью конструктора Object или имеющих цепочку прототипов. Примитивные значения, null, undefined и объекты, созданные с помощью Object.create(null) или помеченные как non-extensible, могут не иметь доступного __proto__.

Что такое __proto__?

__proto__ (произносится как "dunder proto") — это устаревший геттер/сеттер для доступа к внутреннему слоту [[Prototype]] объекта. Внутренний слот [[Prototype]] — это механизм наследования в JavaScript, связывающий объекты в цепочку прототипов.

// Пример работы __proto__
const animal = { eats: true };
const rabbit = { jumps: true };

rabbit.__proto__ = animal; // Установка прототипа (устаревший способ)

console.log(rabbit.eats); // true, через цепочку прототипов
console.log(rabbit.__proto__ === animal); // true

Современные аналоги __proto__

Вместо __proto__ рекомендуется использовать:

  • Object.getPrototypeOf(obj) — получить прототип
  • Object.setPrototypeOf(obj, proto) — установить прототип
  • Object.create(proto) — создать объект с указанным прототипом
// Современный подход
const animal = { eats: true };
const rabbit = Object.create(animal);
rabbit.jumps = true;

console.log(Object.getPrototypeOf(rabbit) === animal); // true
console.log(rabbit.eats); // true

Какие сущности НЕ имеют __proto__?

1. Примитивные значения (кроме объектов-оберток)

Когда вы работаете с примитивами (string, number, boolean, symbol, bigint), они не имеют свойств или методов. Однако при обращении к свойствам JavaScript временно оборачивает их в объекты.

const str = "hello";
console.log(str.__proto__); // String.prototype (работает из-за автоупаковки)
console.log("hello".__proto__); // String.prototype

// Но в строгом смысле примитив сам по себе не имеет __proto__
const primitiveStr = "test";
const strObject = new String("test");

console.log(typeof primitiveStr); // "string" - примитив
console.log(typeof strObject); // "object" - объект

2. null и undefined

Эти значения не являются объектами и не имеют __proto__.

console.log(null.__proto__); // TypeError: Cannot read properties of null
console.log(undefined.__proto__); // TypeError: Cannot read properties of undefined

3. Объекты, созданные через Object.create(null)

Эти объекты не имеют прототипа вообще (их [[Prototype]] равен null).

const objWithoutProto = Object.create(null);
objWithoutProto.name = "Test";

console.log(objWithoutProto.__proto__); // undefined
console.log(Object.getPrototypeOf(objWithoutProto)); // null
console.log(objWithoutProto.toString); // undefined (нет методов Object)

4. Object.prototype — вершина цепочки прототипов

Сам Object.prototype имеет __proto__, равный null.

console.log(Object.prototype.__proto__); // null

5. Объекты с нарушенной цепочкой прототипов

Некоторые объекты могут быть созданы с "битой" цепочкой прототипов.

const obj = {};
Object.setPrototypeOf(obj, null);
console.log(obj.__proto__); // undefined

Практические примеры и различия

// Проверка наличия __proto__
function hasProtoAccess(entity) {
    try {
        // Пытаемся получить доступ к __proto__
        const proto = entity.__proto__;
        return proto !== undefined;
    } catch (error) {
        return false;
    }
}

console.log(hasProtoAccess({})); // true
console.log(hasProtoAccess("string")); // true (автоупаковка)
console.log(hasProtoAccess(null)); // false
console.log(hasProtoAccess(undefined)); // false

const emptyObj = Object.create(null);
console.log(hasProtoAccess(emptyObj)); // false

Почему __proto__ считается устаревшим?

  1. Стандартизация: __proto__ был добавлен браузерами до стандартизации и лишь позже включен в спецификацию ECMAScript для совместимости
  2. Производительность: Прямой доступ к __proto__ может мешать оптимизациям движков JavaScript
  3. Надежность: Использование Object.get/setPrototypeOf делает код более предсказуемым
  4. Безопасность: В строгом режиме ("use strict") некоторые операции с __proto__ могут вызывать ошибки

Рекомендации по использованию

  • Всегда предпочитайте Object.getPrototypeOf() и Object.setPrototypeOf() вместо __proto__
  • Для проверки прототипной связи используйте instanceof или Object.isPrototypeOf()
  • Помните, что __proto__ не является настоящим свойством, а геттером/сеттером в Object.prototype
// Правильный способ работы с прототипами
const parent = { name: "Parent" };
const child = Object.create(parent);
child.age = 10;

// Получение прототипа
const proto = Object.getPrototypeOf(child); // { name: "Parent" }

// Установка прототипа
const newParent = { type: "New Parent" };
Object.setPrototypeOf(child, newParent);

// Проверка связи
console.log(newParent.isPrototypeOf(child)); // true

Вывод

Только объекты с нормальной цепочкой прототипов имеют доступный __proto__. Примитивы, null, undefined и объекты без прототипа (Object.create(null)) либо не имеют __proto__, либо обращение к нему вызывает ошибку. В современной разработке следует использовать стандартные методы Object.getPrototypeOf() и Object.setPrototypeOf() для безопасной и предсказуемой работы с прототипами.

У всех ли сущностей есть __proto__ | PrepBro