Цепочки прототипов - Promise в частности
Всем привет, изучал прототипы, прототипное наследование, и наткнулся в консоли на интересный кейс с промисами, который мучает уже несколько дней.
(Оговорки)
После очередного прочтения источников, предполагаю что:
Prototype
- объект существующий почти в каждой функции (за исключением fetch и подобных);
[[Prototype]]
- внутренний слот каждого объекта в JS - ссылка на родительский Prototype
, доступ к которой можно получить через легаси __proto__
(является геттером и сеттером этой скрытой ссылки);
Пробую эксперементировать. Вывожу экземпляр объекта в devtools, иду по цепочке прототипов до null разными путями:
const obj = new Object;
// Путь constructor-prototype:
// obj -> [[Prototype]]: -> constructor -> prototype -> __proto__: null
// (Ожидаемый результат)
// Путь __proto__, [[Prototype]]:
// obj -> [[Prototype]] -> __proto__ -> __proto__: null
// (Почти ожидаемый результат)
// Делаю выводы:
// 1) __proto__ === constructor.prototype (по определениям)
// 2) prototype === prototype.constructor.prototype
// 3) Возможно переход "obj->[[Prototype]]" это не ссылка на родительский прототип, а
// локальный скрытый объект внутри obj (Потому что если бы возвращался родительский
// прототип, то путь до null был бы короче: obj->[[Prototype]]->__proto__: null).
Решаю далее походить по цепочкам производных встроенных объектов, например промиса:
const p = Promise.resolve();
// Путь constructor-prototype:
// p -> [[Prototype]] -> constructor -> prototype -> [[Prototype]] -> __proto__ -> __proto__: null
// (Почти ожидаемый результат)
// Путь __proto__, [[Prototype]]:
// p -> [[Prototype]]: Promise -> [[Prototype]]: Object* -> __proto__: Promise -> \
// [[Prototype]]: -> __proto__ -> __proto__: null
// (What?)
Откуда в цепи взялся доп.объект*?
Вначале подумал, возможно это какой-то внутренний процесс, и он появляется из-за создания экземпляра промиса, но ведь p.__proto__.__proto__.__proto__ === null
, а значит на деле этого объекта нет...
Является ли instance->[[Prototype]]->*
внутренним объектом этого инстанса, или же объектом родителя? Если объектом родителя, то почему для перехода к "деду" нужно сделать странный мув вроде *->constructor->prototype->[[Prototype]]
или *->[[Prototype]]->__proto__
, а не обычный *->__proto__
(aka *->[[Prototype]]
)?
Наконец, почему иногда встречается __proto__
, а иногда [[Prototype]]
? Можно ли условно считать их однозначными в контексте перемещения к null?
Возможно я не вижу чего-то в упор, но последние дни были несколько тяжёлыми. Буду рад услышать ваши мысли
p.s. Изучил довольно много источников (включая англоязычных), но самым лучшим показалась эта статья https://habr.com/ru/articles/518360/ (опирался на неё)