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 символов:
И, судя по комментарию, он нашёл в 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 символов.