Почему не одобряется модификация прототипов объектов JavaScript? - PullRequest
16 голосов
/ 03 июня 2011

Я тут и там встречал несколько комментариев о том, как неодобрительно изменять прототип объекта JavaScript?Я лично не понимаю, как это может быть проблемой.Например, расширение объекта Array для отображения и включения методов или для создания более надежных методов Date?

Ответы [ 5 ]

23 голосов
/ 03 июня 2011

Проблема в том, что прототип можно модифицировать в нескольких местах.Например, одна библиотека добавит метод map к прототипу Array, а ваш собственный код добавит то же самое, но с другой целью.Таким образом, одна реализация будет нарушена.

10 голосов
/ 03 июня 2011

В основном из-за коллизий пространства имен.Я знаю, что у инфраструктуры прототипов было много проблем с сохранением их имен отличными от тех, которые были включены изначально.

Существует два основных способа предоставления утилит людям ..

Прототипирование

Добавление функции в прототип объекта.MooTools и Prototype делают это.

Преимущества:

  1. Супер легкий доступ.

Недостатки:

  1. Можно использоватьмного системной памяти.В то время как современные браузеры просто извлекают экземпляр свойства из конструктора, некоторые старые браузеры сохраняют отдельный экземпляр каждого свойства для каждого экземпляра конструктора.
  2. Не всегда доступен.

Я имею в виду «недоступно»:

Представьте, что у вас есть NodeList от document.getElementsByTagName, и вы хотите перебрать его.Вы не можете сделать ..

document.getElementsByTagName('p').map(function () { ... });

.. потому что это NodeList, а не Array.Выше приведено сообщение об ошибке типа: Uncaught TypeError: [object NodeList] doesn't have method 'map'.

Следует отметить, что существуют очень простые способы преобразования объектов NodeList и других объектов, подобных массивам, в реальные массивы.

Сбор

Создание новой глобальной переменной и утилит складирования на ней.Это делают jQuery и Dojo.

Преимущества:

  1. Всегда там.
  2. Низкое использование памяти.

Недостатки:

  1. Не так хорошо расположен.
  2. Может быть неудобно использовать время от времени.

С этим методом вы все равно не справитесь ..

document.getElementsByTagName('p').map(function () { ... });

.. но вы могли бы сделать ..

jQuery.map(document.getElementsByTagName('p'), function () { ... });

.. но, как указал Мэтт, при обычном использовании вы бы сделали выше с ..

jQuery('p').map(function () { ... });

Что лучше?

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

6 голосов
/ 03 июня 2011

Как отметил Бьорнд, monkey-patching является проблемой только тогда, когда задействовано несколько библиотек. Поэтому это не очень хорошая практика, если вы пишете библиотеки многократного использования. Тем не менее, это все еще остается лучшим методом для устранения проблем совместимости между браузерами при использовании хост-объектов в javascript.

См. эту ссылку , где описана настоящая авария при совместном использовании prototype.js и json2.js.

1 голос
/ 10 декабря 2016

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

Поддерживаемый JavaScript: не изменяйте объекты, которые вам не принадлежат: https://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/

0 голосов
/ 17 мая 2019

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

Это именно то, что произошло с Array.prototype.flatten и Array.prototype.contains.Вкратце, для этих методов была составлена ​​спецификация, их предложения дошли до стадии 3 , а затем браузеры начали ее отправлять.Но в обоих случаях было обнаружено, что существуют древние библиотеки, которые исправляли встроенный объект Array своими собственными методами с тем же именем, что и новые методы , и имели другое поведение;в результате веб-сайты сломались, браузерам пришлось отказаться от реализации новых методов, а спецификацию пришлось редактировать.(Методы были переименованы.)

Например, в настоящее время существует предложение для String.prototype.replaceAll .Если вы отправляете библиотеку, которая широко используется, и эта библиотека монтирует нестандартный метод custom на String.prototype.replaceAll, то имя replaceAll больше не будет использоваться авторами спецификаций;его нужно изменить, прежде чем браузеры смогут его реализовать.

...