JS __proto__ «забавный» факт

Nov 26 2022
Если вы следили за мной достаточно долго, вы уже знаете, насколько я всегда был против __proto__, и тем не менее, поскольку он уже давно стал стандартом ECMAScript, все еще есть редкие случаи, когда я нахожу, по крайней мере, его использование для обозначения объекта. приемлемо: отбросив производительность, и обратите внимание, что я вообще не предлагаю использовать __proto__ в дикой природе, этот пост существует по другим причинам. Объект.
Фото Марка Уильямса на Unsplash

Если вы следили за мной достаточно долго, вы уже знаете, насколько __proto__я всегда был против, и все же, поскольку он уже давно стал стандартом ECMAScript , все еще есть редкие случаи, когда я нахожу, по крайней мере, его использование для маркировки объекта приемлемым :

const factory = (fields, {prototype} = Object) => ({
  __proto__: prototype,
  ...fields
});

// mimic an <a /> reference
factory({href: '/'}, HTMLAnchorElement);

В Firefox __proto__ оценивается лучше, чем новый класс

Отложив производительность в сторону, и обратите внимание, что я вообще не предлагаю использовать __proto__в дикой природе, этот пост существует по другим причинам.

Объект.прототип.__прото__

Я почти уверен, что все знают, что делает аксессор __proto__ , поэтому я хотел бы предложить вам вызов… и да, это все допустимый JS:

class Test {}
const __proto__ = Test.prototype;

// what do these operations return?
({__proto__} instanceof Test);
({__proto__: __proto__} instanceof Test);
({"__proto__": __proto__} instanceof Test);
({["__proto__"]: __proto__} instanceof Test);

// what do these operations return?
({__proto__}.__proto__ === Test.prototype);
({__proto__: __proto__}.__proto__ === Test.prototype);
({"__proto__": __proto__}.__proto__ === Test.prototype);
({["__proto__"]: __proto__}.__proto__ === Test.prototype);

Если вы еще не запустили эти фрагменты, чтобы узнать ответ, я могу помочь с этим! В первом вызове на выходе будет false, true, trueи falseснова, и причина в том, что и то, {__proto__}и другое {["__proto__"]}определяется как собственное свойство , а присваивание через синтаксис, без использования специальных синтаксических возможностей, даже с кавычками, проходит фактически через Object.prototype.__proto__аксессор.

С другой стороны, во втором вызове (all true) на самом деле не имеет значения, обращаемся ли мы __proto__напрямую или как ["__proto__"], так что в основном существует нулевая симметрия в том, как мы можем запускать __proto__сеттер, по сравнению с тем, как мы можем запускать __proto__геттер один раз . это либо собственная собственность, либо волшебные ворота наследства.

… и не только __proto__

Я не проверял себя, но я считаю, что каждый устаревший __xxx__специальный метод доступа страдает от одного и того же __proto__проклятия, поэтому, пожалуйста, будьте осторожны, смешивая новейший классный синтаксис JS для назначения свойств с вашими фактическими намерениями и ожиданиями, так как все может легко пойти не так, если вы попытаетесь будьте умны в назначении этих свойств .

И это все люди!

Единственный вывод из этого поста, вероятно, можно резюмировать так:

  • не используйте устаревшие, но работающие части языка, если вы хотите избежать сюрпризов сегодня или завтра в отношении того, как они ведут себя с новым синтаксисом
  • предпочитать явный (и, к сожалению, более медленный) Object.setPrototypeOfвсякий раз, когда строго требуется ручная установка прототипа объекта, но использовать классы во всех остальных случаях, когда это возможно
  • сотрите из своей памяти этот пост или сократите его до короткого предложения, например: « Я никогда не должен использовать __proto__в своем коде », и продолжайте изучать новые причудливые вещи, которые не испортят ваш мозг или чувства .