Расширение Natives в JavaScript

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

JavaScript невероятно гибкий и красивый язык (но имеющий и свои проблемы ессно) и меня невероятно огорчает, что я не имею возможности использовать весь его потенциал. Жестким ограничем на NOE была отрезана огромная и важная часть возможностей языка. Да, расширять нативные объекты - это преступление против разума, но "не делать этого" - точно такое же преступление против самого языка. Уверен, если бы многие это понимали, то мы бы уже давно имели некий компромиссный вариант, который позволял бы нам использовать NOE хотя бы локально (в контексте). Вместо этого все просто закрыли эту тему, выставив на неё "табу".

Есть такая библиотека под названием SugarJS. Именно благодаря ей я узнал насколько лаконичным и понятным может быть код на JS. Благодаря NOE и креативному подходу создателей данная библиотека имеет потрясающий интерфейс, который позволяет этого добиться. Стоит также отметить невероятное удобство использования этой библиотеки вместе с AngularJS. А работа с Date'ами превращается просто в настоящий праздник, даже если сравнивать не только с нативным решением, но и с самыми известными альтернативными библиотеками вроде moment.js.

Давайте рассмотрим небольшой искусственный пример, чтобы оценить различные подходы.

Данный код написан из допущения, что все приведенные библиотеки были бы написаны с одинаковыми возможностями (что не является правдой). Это необходимо, чтобы сфокусироваться именно на стиле написания кода, а не на функциональных особенностях.

var users = [ // sample data from lodash docs
    { 'name': 'barney', 'age': 36 },
    { 'name': 'fred',   'age': 40 }
];
// COMPARISON, sugar style
var max = users.map('age').max();
// VS underscore style
var max = _.max(_.map([1.34,-2.34,5], 'age'));
// VS lodash chain style
var max = _.chain(users).map('age').max().value();

Очевидно, что подход SugarJS существенно выигрывает по сравнению с остальными, которые на его фоне выглядят костылями (ИМХО ими и являются). Однако, такой подход имеет ряд проблем, которые создатели SugarJS изо всех сил попытались обойти о чем подробно написали в своём манифесте.

Если обобщать, то использование SugarJS на данный момент имеет следующую цену:

Вам придется обеспечивать актуальную версию SugarJS в вашем проекте. Фиксирование версии может привести к проблемам. Это относится и к другим библиотекам (lodash и т.д.), хоть и в меньшей степени. Имеется маленький шанс, что вам придется переписать часть кода, когда браузеры обновят спецификацию. Не могу припомнить, чтобы это когда-то было нужно. Интерфейс SugarJS менее гибкий в плане добавления нового функционала нежели альтернативные библиотеки не использующие NOE. Хотя текущего функционала хватает для подавляющего большинства задач. Высмеивания и тыкания пальцем со стороны людей, которые узнают, что вы используете SugarJS. Также вероятность холивара в компании, где вы его используете. Самая большая и неприятная проблема из этого списка. Лично для меня эти минусы (кроме последнего) абсолютно несущественны, если учесть какие преимущества даёт SugarJS. Общая вероятность того, что у меня перестанет работать сайт после выхода новой версии браузера все равно на порядки больше, чем та же поломка по вине SugarJS. Разумеется я рассматриваю серьезный сайт с большим количеством библиотек, а не свою домашнюю страничку. Это не предположение, это по опыту. Поломку используемых мною библиотек я видел многократно. А SugarJS подвёл меня все лишь раз, но как выяснилось лишь потому, что я зафиксировал его версию и три месяца не обновлял.

В качестве заключения хочу сказать, что разумеется нужно избегать использования bad practices. Но как показывает опыт не существует ничего, что является абсолютным злом (даже goto и eval). Всегда нужно адекватно оценивать минусы и плюсы. И уж точно ваш код не должен превращаться в нечитабельный винегрет из-за неукоснительного следования good practices (да, такое бывает, см. выше), когда этого можно избежать небольшой ценой.