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

От какого прототипа наследуются типы данных

2.3 Middle🔥 111 комментариев
#JavaScript Core

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

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

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

Цепочка прототипов и наследование типов данных в JavaScript

В JavaScript все типы данных, включая примитивы, наследуются от базового прототипа Object.prototype, который находится на вершине цепочки прототипов. Это фундаментальный принцип языка, где почти всё является объектом.

Иерархия наследования

Вот как выглядит основная цепочка прототипов:

// Проверим цепочку наследования для массива
const arr = [];
console.log(arr.__proto__ === Array.prototype); // true
console.log(arr.__proto__.__proto__ === Object.prototype); // true
console.log(arr.__proto__.__proto__.__proto__); // null

// Проверим для числа
const num = 42;
console.log(num.__proto__ === Number.prototype); // true
console.log(num.__proto__.__proto__ === Object.prototype); // true

Специфические прототипы для разных типов

Каждый тип данных имеет свой собственный прототип, который в свою очередь наследует от Object.prototype:

  1. Array.prototypeObject.prototype
  2. String.prototypeObject.prototype
  3. Number.prototypeObject.prototype
  4. Boolean.prototypeObject.prototype
  5. Function.prototypeObject.prototype
  6. Date.prototypeObject.prototype
  7. RegExp.prototypeObject.prototype

Особенности примитивных типов

Интересный нюанс: примитивные типы (string, number, boolean, symbol, bigint, undefined, null) технически не являются объектами, но когда к ним обращаются как к объектам (через точечную нотацию), JavaScript автоматически создаёт временный объект-обёртку:

const str = "hello";
// При вызове метода JavaScript создает временный объект String
console.log(str.toUpperCase()); // "HELLO"

// Эквивалентно:
const tempString = new String(str);
console.log(tempString.toUpperCase());
// Временный объект уничтожается после выполнения операции

Проверка прототипной цепочки

// Проверим всю цепочку наследования для функции
function example() {}

console.log(example.__proto__ === Function.prototype); // true
console.log(example.__proto__.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null - конечная точка

// Метод для проверки прототипа
console.log(Object.getPrototypeOf([]) === Array.prototype); // true
console.log(Object.getPrototypeOf(Array.prototype) === Object.prototype); // true

Особый случай: null и undefined

Есть два исключения из общего правила:

  • null и undefined не имеют прототипов и методов
  • При попытке доступа к их свойствам возникает ошибка
console.log(Object.getPrototypeOf(null)); // null
console.log(Object.getPrototypeOf(undefined)); // undefined

// Попытка доступа к свойствам вызывает ошибку
// null.toString(); // TypeError
// undefined.toString(); // TypeError

Практическое значение

Понимание прототипного наследования критически важно для:

  • Расширения встроенных типов (хотя это считается антипаттерном)
  • Создания собственных иерархий объектов
  • Оптимизации производительности (цепочек прототипов лучше избегать глубоких)
  • Правильного использования методов наследования
// Пример расширения функциональности (с осторожностью!)
if (!Array.prototype.customMethod) {
  Array.prototype.customMethod = function() {
    return this.length * 2;
  };
}

const myArray = [1, 2, 3];
console.log(myArray.customMethod()); // 6

Прототип vs Классы (ES6)

С появлением классов в ES6 прототипная модель стала менее явной, но не исчезла:

class MyClass {
  constructor(value) {
    this.value = value;
  }
  
  getValue() {
    return this.value;
  }
}

const instance = new MyClass(10);
console.log(instance.__proto__ === MyClass.prototype); // true
console.log(MyClass.prototype.__proto__ === Object.prototype); // true

Таким образом, хотя синтаксис изменился, под капотом по-прежнему работает прототипное наследование, где все цепочки в конечном итоге ведут к Object.prototype. Это один из ключевых аспектов JavaScript, который отличает его от классических объектно-ориентированных языков.