Почему расширение DOM / встроенных прототипов объектов - плохая идея?


15

Я ищу окончательный ответ на вопрос, почему расширение встроенных прототипов так жестко наказывается в сообществе разработчиков JS. Я уже давно использую Prototype JS Framework, и мне [1,2,3].each(doStuff)кажется, что делать это гораздо элегантнее $.each([1,2,3], doStuff). Я знаю, что это создает «загрязнение пространства имен», но я все еще не понимаю, почему это считается плохой вещью. Также существует ли реальное снижение производительности, связанное с расширением встроенных прототипов? Благодарность!


1
Одна вещь состоит в том, что for(var ... in ...)циклы перепутаны, так как функции прототипа также передаются.
pimvdb

4
"сильно наказан", правда ?! Боже, мужик:] ты в порядке?
pixelbobby

Ответы:


12

Я предлагаю вам прочитать эту статью, которая, я думаю, довольно хорошо объясняет, почему расширение объектов является плохой идеей, в том числе и в отношении Prototype.

В итоге:

Отсутствие спецификации

Экспозиция «объектов-прототипов» не является частью какой-либо спецификации. [...] Чтобы реализация полностью соответствовала DOM Level 2, нет необходимости показывать эти глобальные объекты Node, Element, HTMLElement и т. Д.

Хост-объекты не имеют правил

Объекты DOM являются объектами хоста [...] Объекты хоста могут реализовывать эти внутренние методы с любым поведением, зависящим от реализации, или может быть так, что объект хоста реализует только некоторые внутренние методы, а не другие.

[...] Поведение внутренних методов зависит от реализации. [...] По определению, вы работаете с чем-то, что может вести себя непредсказуемо и совершенно беспорядочно.

Возможны столкновения

Учитывая огромное количество сред, используемых сегодня, становится невозможным определить, не является ли определенное свойство уже частью некоторого DOM. [...]

Каждая именованная форма управляет свойствами теней, унаследованными через цепочку прототипов. Вероятность столкновений и неожиданных ошибок на элементах формы еще выше.

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

Накладные расходы

[...] браузеры, которые не поддерживают расширения элементов - такие как IE 6, 7, Safari 2.x и т. д. - требуют ручного расширения объекта. Проблема в том, что ручное расширение медленное, неудобное и не масштабируется.

[...] как только вы начнете расширять элементы, библиотечный API, скорее всего, должен будет везде возвращать расширенные элементы. В результате запросы таких методов, как $$, могут в конечном итоге расширить каждый элемент в запросе.

IE DOM беспорядок

Как показано в предыдущем разделе, ручное расширение DOM - беспорядок. Но ручное расширение DOM в IE еще хуже [...]

Бонус: ошибки браузера


9

Другой причиной является удобочитаемость кода. Если другой разработчик (особенно новичок) читает мой код и видит [0, 1, 2].foo(...), они могут не знать, что такое метод foo или где найти документацию / источник для него. Является ли foo расширением языка, добавленного prototype.js, или другой используемой библиотекой, или какой-то другой частью моего кода в другом файле, или это родной метод JavaScript, о котором они не знали? Они должны охотиться за ним и могут не найти его сразу (или, если есть конфликты, они могут не найти правильный).

С подходом jQuery, если вы видите $.foo(...), пространство имен метода foo делает очевидным, где найти его определение / документацию, если вы не знаете, что он делает.


Обнаружение того, откуда берутся методы, очень важно для читателей. Хотя я на самом деле не думаю, что jQuery - хороший пример, так как знак доллара затрудняет поиск, когда вы начинаете читать веб-код и еще не знаете, что это такое.
Симон

4

Вот основная проблема: что произойдет, если у вас есть два инструмента, которые расширяют прототипы несовместимыми способами, или которые расширяют обычно вызываемые методы таким образом, чтобы они давали разные результаты (это особая проблема для for...inJavaScript), таким образом вызывая код, который полагается от их нормального поведения нарушать?

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

Конечно, prototype.js довольно хорошо известен, и большинство инструментов работают вокруг того, что он делает. Точно так же я уверен, что есть случаи, когда расширение базовых прототипов является правильным решением. Но к этому нужно подходить с осторожностью.


1

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


1

Здесь есть два отдельных вопроса. Первый - это общее расширение встроенных прототипов, а второй - расширение DOM-прототипов. Аргументы против расширения встроенных прототипов:

  • Потенциальные конфликты: два фрагмента кода из разных источников, определяющих одно и то же свойство в одном и том же прототипе
  • Побочные эффекты: расширение Array.prototypeили Object.prototypeможет вызывать эффекты, такие как добавление методов расширения, перечисляемых в for...inцикле

Что касается расширения прототипов DOM, то приведенный выше аргумент потенциального конфликта все еще применяется. Кроме того, узлы DOM являются хост-объектами и, как таковые, не подпадают под действие каких-либо нормальных правил собственных объектов JavaScript. По сути, они могут делать то, что им нравится, и не обязаны предоставлять разумные объекты-прототипы или даже разрешать дополнительные ("расширенные") свойства. IE , в частности , упражнения этого права, не предоставляя прототипов DOM объектов , прежде чем IE 9 и имеющий различные weirdnesses о свойствах на различных объектах DOM (хотя вы обычно OK Назначение свойства элементов, при условии , набора Ничего document.expandoк false.)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.