У всех ли сущностей есть __proto__
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Развернутый ответ: __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__ считается устаревшим?
- Стандартизация:
__proto__был добавлен браузерами до стандартизации и лишь позже включен в спецификацию ECMAScript для совместимости - Производительность: Прямой доступ к
__proto__может мешать оптимизациям движков JavaScript - Надежность: Использование
Object.get/setPrototypeOfделает код более предсказуемым - Безопасность: В строгом режиме (
"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() для безопасной и предсказуемой работы с прототипами.