Return True

09. Proto1

function proto1(x) {
  return x && !("__proto__" in x);
}

В прошлой задаче мы уже касались темы того, что __proto__ нельзя удалить из объекта, потому что он берётся из его прототипа. Потому сразу может быть и не очевидно, как же нам тогда поступить. Как удалить __proto__ из объекта, чтобы его там не было?

Раз оно берётся из прототипа, то может быть просто подменить прототип на null, чтобы его не было?

proto1({__proto__:null})

Вжух! И внезапно работает! 16 символов. Почти самое короткое решение!

Но почему? Ведь __proto__ в объекте есть, просто он равен null. А всё дело в том, что за in отвечает проверка OrdinaryHasProperty, суть которой в том, что она перебирает объекты в цепочке прототипов в поиске того, в котором это поле есть. И ищет до тех пор, пока не наткнётся на прототип равный null. А поскольку __proto__ — это и есть ссылка на прототип, то алгоритм завершается, когда на неё натыкается.

Можно было бы сказать, что спецификация должна предусматривать такой вариант развития событий, и сделать исключение для __proto__, добавив дополнительную проверку. Но __proto__ — костыль, и было бы странно размазывать его по всем частям спеки.

Более легитимный вариант решения, выглядел бы вот так:

proto1(Object.create(null))

Но он длиннее на 3 символа, потому нас не интересует.


В таблице результатов есть пользователь с решением в 8 символов:

Топ пользователей по задаче proto1

И, судя по комментарию, он нашёл в 12-м Эдже что-то, что обладает теми же свойствами, но при этом умещается всего в 8 символов.

К сожалению, проверить это без каких-то суровых костылей не предоставляется возможным, так как политика Майкрософта (как и остальных компаний) в том, что они не предоставляют старые сборки браузеров. Наверное такое решение играет какую-то роль в плане безопасности, но это очень неудобно.

Тем не менее, быстрый поиск среди глобальных объектов в ИЕ 11 показывает, что такой элемент есть:

> for (var key in window) {
>   try {
>     if (window[key] && !('__proto__' in window[key])) {
>       console.log(key);
>     }
>   } catch(err) {}
> }
external

window.external — это устаревший интерфейс для добавления дополнительных поисковых провайдеров. В ИЕ 11 он сделан как-то криво, и потому у него вообще нет поля __proto__:

> window.external.__proto__
undefined

Вероятнее всего, реализация этого интерфейса в 12-м Эдже была аналогичной.

Увы, использовать Интернет Эксплорер для того, чтобы отправить это решение, у нас не получится, т. к. для работы сайта нужна поддержка промисов, а там её нет. Теоретически, можно что-то где-то подхачить и подпереть, чтобы заставить всё это работать. Ну или использовать Браузерстэк или пиратскую Виндоус 8 нужной версии. Но настолько изощрённые методы пусть останутся самым любознательным. Пока что с уверенностью можно утверждать, что external — решение задачи в 8 символов.