Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Расширение прототипов встроенных обьектов: хорошо или плохо? (https://javascript.ru/forum/misc/4646-rasshirenie-prototipov-vstroennykh-obektov-khorosho-ili-plokho.html)

hogart 10.08.2009 18:33

Расширение прототипов встроенных обьектов: хорошо или плохо?
 
Неоднократно слышал от уважаемых мною людей, что Prototype.js — некошерно, потому что изменяет прототипы встроенных обьектов.
Недавно почитал про MooTools, и оказалось, что они тоже используют этот подход, более того, предоставляют удобный интерфейс для расширения прототипов.

И у меня закрались сомнения.

Действительно ли плохо менять встроенные прототипы? Чем это плохо, кроме того, что возможно, при подключении еще одного фреймворка, возникнут конфликты?

Какие подводные камни?

Kolyaj 10.08.2009 18:59

Цитата:

Сообщение от hogart
Prototype.js — некошерно

Prototype не кошерно, потому что они JavaScript не знают :) Смотрите, например, реализацию метода each для массивов.

По теме: юзаю активно.

hogart 10.08.2009 19:03

Цитата:

Сообщение от Kolyaj (Сообщение 26380)
Prototype не кошерно, потому что они JavaScript не знают :) Смотрите, например, реализацию метода each для массивов.

Лень, если честно, поверю на слово:)

Цитата:

Сообщение от Kolyaj (Сообщение 26380)
По теме: юзаю активно.

А какой фреймворк (если есть)? И какие трудности возникали, если возникали?

Спасибо.

Kolyaj 10.08.2009 19:23

Цитата:

Сообщение от hogart
А какой фреймворк (если есть)?

Во фреймворках, как правило, все для жизни имеется, там что-то дополнительно расширять не надо. В pure скриптах расширяю. Там, где требуется максимальная изолированность, разумеется не расширяю.

Цитата:

Сообщение от hogart
И какие трудности возникали, если возникали?

Если я использую сторонний фреймворк, я его всегда могу пропатчить/удалить в случае чего. Если я пишу фреймворк, который будет использоваться сторонними разработчиками, проблемы, разумеется могут быть, но не у меня :)

hogart 10.08.2009 19:32

Kolyaj, удалить? а если уже полмегабайта скриптов написано с расчетом на этот фреймворк?

Kolyaj 10.08.2009 19:39

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

hogart 10.08.2009 21:33

Kolyaj, это-то очевидно.

Kolyaj 10.08.2009 21:44

А какие еще могут возникнуть проблемы?

Dmitry A. Soshnikov 10.08.2009 23:06

hogart, пока нельзя задавать внутреннее свойство {DontEnum} добавляемым методам/свойствам, не советуют расширять Object.prototype и Array.prototype. Причина: оператор in найдёт эти свойства в "пустых" объектах. В остальном - это в идеологии языка, поэтому - смело можно расширять всё, что захочется.

Kolyaj 10.08.2009 23:08

Цитата:

Сообщение от Dmitry A. Soshnikov
и Array.prototype

А по массивам не надо бегать for-in, у них есть (везде, кроме ИЕ) метод forEach.

Андрей Параничев 10.08.2009 23:17

А вот мне кажется, что расширение прототипов встроенных объектов только вводит путаницу в код.

Dmitry A. Soshnikov 10.08.2009 23:22

Цитата:

Сообщение от Kolyaj
А по массивам не надо бегать for-in

Я в курсе ;) А вообще - почему "не надо"?

Цитата:

Сообщение от Андрей Параничев
А вот мне кажется, что расширение прототипов встроенных объектов только вводит путаницу в код.

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

Kolyaj 10.08.2009 23:26

Ну тут сначала нужно разделить случаи. Первый -- это нивелирование различий браузеров: тот же forEach (да и остальные методы, кроме reduce-reduceRight) везде есть, в ИЕ нет. Второй случай -- добавление своих методов. Тут я тоже не вижу путаницы. Простой и полезный метод last, например,
var lastElem = getMyArray().last();
Где тут путаница?

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

Андрей Параничев 10.08.2009 23:41

Kolyaj,
Я бы реализовал функцию last(), а не метод в прототипе. Чтобы у других программистов не возникало вопросов при просмотре, например, такого кода:
var myArray = ["some", "thing", "here"];
doSomething(myArray.last())

Тут может быть непрозрачно, откуда взялся этот ласт. Но пример утрирован, конечно.

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

Kolyaj 10.08.2009 23:49

Цитата:

Сообщение от Андрей Параничев
откуда взялся этот ласт

Оттуда же, откуда взялась бы функция. Ты ведь знаешь стандартные методы Array? Знаешь, что там нет last? Значит он где-то в проекте реализован. Значит можно кликнуть колесиком и перейти к реализации ))) Мы ведь, надеюсь, не говорим о тех, кто не знает JavaScript? А если ты не знаешь JS, значит ты не можешь быть уверен, откуда взялась и функция last.

Цитата:

Сообщение от Андрей Параничев
Я бы реализовал функцию last()

Вложенный вызов функций читается хуже цепочки методов.

hogart 11.08.2009 19:59

Цитата:

Сообщение от Kolyaj
А какие еще могут возникнуть проблемы?

Вот я и спрашиваю, какие еще могут возникнуть проблемы?:)

hogart 11.08.2009 20:03

Цитата:

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

Почему, почему, почему? Ведь очевидно, что две библиотеки подключают только очень небрежные люди.

Kolyaj 11.08.2009 20:28

Цитата:

Сообщение от hogart
Вот я и спрашиваю, какие еще могут возникнуть проблемы?

Ну тогда лично я не вижу проблем :)

hogart 11.08.2009 20:30

Kolyaj, я, вроде бы, тоже. Но не хочется опираться только на собственную самоуверенность в таком достаточно фундаментальном вопросе:)

Zeroglif 11.08.2009 22:26

Цитата:

Сообщение от hogart (Сообщение 26378)
1) Действительно ли плохо менять встроенные прототипы?

2) Чем это плохо, кроме того, что возможно, при подключении еще одного фреймворка, возникнут конфликты?

3) Какие подводные камни?

1) 2) 3) Наверное не "менять прототипы", а расширять прототипы. Удобное, компактное расширение - идея прототипов, это хорошо. Плохо, когда причиной расширения становится не реюз и компактность, а "типа-объектное-программирование-чтоб-было" - любую мелкую задачу через Object. Раздражает прежде всего контроль за именами.

hogart 11.08.2009 23:50

Zeroglif, да, конечно, расширять, я неверно выразился.

Цитата:

Сообщение от Zeroglif
любую мелкую задачу через Object

насколько мелкую?

Цитата:

Сообщение от Zeroglif
Раздражает прежде всего контроль за именами.

Что вы имеете ввиду?

hogart 12.08.2009 23:31

В общем, как всегда на этом форуме, — получил кучу очевидных ответов и туманных общих замечаний, и ничего нового. Печально, господа.
Неужели мы тут только для того, чтобы высокомерно отвечать новичкам, которые не то что JS, русского языка-то не знают?

Dmitry A. Soshnikov 12.08.2009 23:45

hogart, почему туманных? Здесь были и конкретные ответы/советы. Можно ещё раз:

Цитата:

Сообщение от hogart
Действительно ли плохо менять встроенные прототипы?

Нет, не плохо, к тому же - заложено в идеологию языка. JS - динамический язык.

Цитата:

Сообщение от hogart
Чем это плохо, кроме того, что возможно, при подключении еще одного фреймворка, возникнут конфликты?

Какие подводные камни?

Подводные камни:

- конфликт имён (подключение нескольких библиотек, но здесь - не важно - в прототипе описано или нет - в двух фреймворках может быть и две глобальные переменные, как, например, $);
- в идеале, нужна документация для других программистов;
- расширять Object.prototype не следует;
- расширять Array.prototype можно, но тогда будет ограничение на итерацию по массивам через for ... in (либо, использовать в паре с .hasOwnProperty, либо "индексный" цикл (for var k = 0; k < .. ; k++), либо методы типа .forEach).

Что смущает?

hogart 13.08.2009 00:03

Dmitry A. Soshnikov, ага, вот это уже лучше. Давайте обсудим.

Цитата:

Сообщение от Dmitry A. Soshnikov
Нет, не плохо, к тому же - заложено в идеологию языка. JS - динамический язык.

Ок, согласен.
Но, например, Python — тоже динамический язык, и в нем точно так же можно дополнять/менять поведение встроенных типов, но там это считается дурным тоном — и есть типы, аналогичные встроенным, но предназначенные для наследования/переопределения.

Цитата:

Сообщение от Dmitry A. Soshnikov
- в идеале, нужна документация для других программистов;

в идеале она нужна (читай «должна быть») всегда (и это одна из тех очевидных вещей, о которых я говорил). В идеале, видя коммит без комментов, я должен пойти и дать по шапке за такое.

Цитата:

Сообщение от Dmitry A. Soshnikov
- расширять Array.prototype можно, но тогда будет ограничение на итерацию по массивам через for ... in (либо, использовать в паре с .hasOwnProperty).

Не могу себе представить, зачем бы мне понадобилось итерировать по массивам через for..in.

Dmitry A. Soshnikov 13.08.2009 00:16

Цитата:

Сообщение от hogart
Но, например, Python — тоже динамический язык, и в нем точно так же можно дополнять/менять поведение встроенных типов, но там это считается дурным тоном — и есть типы, аналогичные встроенным, но предназначенные для наследования/переопределения.

Да ладно? В Питоне, в отличии от JS (или Ruby), нельзя расширять встроенные классы. Расширьте-ка, object. Или dict. Или ещё что. Наследоваться - это одно, а расширять - другое.

Цитата:

Сообщение от hogart
в идеале она нужна (читай «должна быть»)

Я отметил в плане "подводных камней". Если будет метод массива [].last(), кто-нибудь (пришедший, например, из статических языков) может подумать, что это стандартный метод и потом использует в другом проекте, где никакого .last уже не будет. С другой стороны, если известны стандартные методы, можно сразу определить, что это - расширение.

Цитата:

Сообщение от hogart
Не могу себе представить, зачем бы мне понадобилось итерировать по массивам через for..in.

Вы про Питон упомянули? Там Вы for ... in не пользовались? ;)

hogart 13.08.2009 00:30

Цитата:

Сообщение от Dmitry A. Soshnikov
нельзя расширять встроенные классы

Да, это я не подумавши ляпнул, извините. Хорошо, возьмем не встроенные классы, а встроенные функции.
И опять таки — расширение встроенных классов запрещено на уровне языка. Хотя большинство питонистов все-таки более сознательны, чем люди, приходящие в JS.

Цитата:

Сообщение от Dmitry A. Soshnikov
кто-нибудь (пришедший, например, из статических языков)

какая-то очень эфемерная опасность. Нужно найти еще сишника, который не прочтет мануалы, перед тем как писать на неизвестном языке — а такие не выживают:)

Цитата:

Сообщение от Dmitry A. Soshnikov
Вы про Питон упомянули? Там Вы for ... in не пользовались?

А там есть for (i = 0; i < 10; i++)?

Андрей Параничев 13.08.2009 01:41

hogart,
Я, например, не вижу задач, которые бы рационально было решать с помощью расширения прототипов встроенных объектов. Ну, возможно, кроме маленьких вспомогательных методов, вроде last(), или методов для обеспечения кросс-браузерности.

Я бы не хотел встретиться в коде с такой конструкцией:
var a = [];
a.loadDOMNodes("div.someclass");

Даже если будет один фреймворк в проекте.

Dmitry A. Soshnikov 13.08.2009 11:34

Цитата:

Сообщение от hogart
Хорошо, возьмем не встроенные классы, а встроенные функции

А что с ними "не так"? Их можно "расширить"?

Цитата:

Сообщение от hogart
И опять таки — расширение встроенных классов запрещено на уровне языка

Всего лишь - одна из реализаций. А в JS и Ruby - не запрещено, и что?

Цитата:

Сообщение от hogart
А там есть for (i = 0; i < 10; i++)?

Нет, там нет такого цикла. Кстати сказать, если расширен Array.prototype, я использую индексный цикл или .forEach (нежели, естественно, for...in и .hasOwnProperty).

И ещё, в JS (с версии 1.7) достпен Array comprehensions (который позаимствован из Питона), и там используется синтаксис for / for each ... in:

var evens = [i for each (i in [1, 2, 3, 4]) if (i % 2 == 0)];


Андрей Параничев, мне кажется, вторая запись более наглядна, определяет сразу принадлежность метода, нежели первая, глобальная функция:

- removeFromArray(array, object);
- array.remove(object);

А если, ещё назовут не removeFromArray а просто remove - думай потом, к чему этот remove относится (но это уже, конечно, мифический случай)?

Kolyaj 13.08.2009 11:57

Цитата:

Сообщение от Dmitry A. Soshnikov
индексный цикл или .forEach (нежели, естественно, for...in и .hasOwnProperty).

И все три способа в общем случае дадут разный результат.

hogart 13.08.2009 12:39

Цитата:

Сообщение от Dmitry A. Soshnikov
Нет, там нет такого цикла.

Вот именно.

Dmitry A. Soshnikov 13.08.2009 12:55

Цитата:

Сообщение от hogart
Вот именно.

;)

Ну, Вы получили ответ на первоначальный вопрос? Картина прояснилась?

hogart 13.08.2009 13:07

Dmitry A. Soshnikov, я так и не понял, зачем вы приводите параллель между питоновским for..in и JS-ным:)

Dmitry A. Soshnikov 13.08.2009 13:12

Цитата:

Сообщение от hogart
я так и не понял, зачем вы приводите параллель между питоновским for..in и JS-ным

Для примера (как подводный камень расширения Array.prototype). В целом же, никто не может утверждать, что for ... in нельзя / "не надо" использовать для массивов - это обычная конструкция, почему нет? А что, for ... in в Питоне и for ... in в JS - это такие мега-разные вещи, что между ними нельзя проводить параллель? К тому же, это не касается первоначального вопроса. Так с первоначальным-то вопросом разобрались (простите, что спрашиваю в очередной раз)?

hogart 13.08.2009 13:20

Цитата:

Сообщение от Dmitry A. Soshnikov
А что, for ... in в Питоне и for ... in в JS - это такие мега-разные вещи

достаточно разные, на мой взгляд.

Цитата:

Сообщение от Dmitry A. Soshnikov
Так с первоначальным-то вопросом разобрались (простите, что спрашиваю в очередной раз)?

Вы достаточно аргументированно и обширно высказали свое мнение, спасибо:)

Dmitry A. Soshnikov 13.08.2009 13:36

Цитата:

Сообщение от hogart
на мой взгляд.

Ну, "имхо" не возбраняется никогда ;)

Цитата:

Сообщение от hogart
достаточно разные

А всё же, мне интересно, покажите, в чём?

hogart 13.08.2009 13:50

Цитата:

Сообщение от Dmitry A. Soshnikov
А всё же, мне интересно, покажите, в чём?

в питоне for..in обходит список (или, скорее итератор:)). в JS for..in обходит словарь. Массив, конечно, можно назвать частным случаем словаря, но как-то не хочется.
И, чисто практическое соображение: массив в JS экономичнее обходится через старый добрый «сишный» for.:)

Dmitry A. Soshnikov 13.08.2009 14:09

Цитата:

Сообщение от hogart
в питоне for..in обходит список (или, скорее итератор). в JS for..in обходит словарь

Python:

for (key, value) in {'a': 1, 'b': 2}.items():
    print(key, value) # a 1, b 2

for key in {'a': 1, 'b': 2}:
    print(key); # a, b


JS (1.7):

for (var [key, value] in {a: 1, b: 2}) {
    alert([key, value]); // a,1 ; b,2
}

for (var key in {a: 1, b: 2}) {
    alert(key); // a; b
}


for / for each ... in равно так же может обходить и массив, не только объект (см., опять же, array comprehensions).

var a = [1, 2];
for (var key in a) {
    alert([key, a[key]]); // 0,1; 1,2
}


Цитата:

Сообщение от hogart
И, чисто практическое соображение: массив в JS экономичнее обходится через старый добрый «сишный» for

Ага, т.к. не анализируется цепь прототипов, но это уже в сторону преимуществ, а не мега-отличий ;)

hogart 13.08.2009 18:12

Давайте не будем про JS 1.7. Если вы имеете счастье на нем писать, то я рад за вас.

Dmitry A. Soshnikov 13.08.2009 18:35

Цитата:

Сообщение от hogart
Давайте не будем про JS 1.7

Давайте.

JS (1.5)

for (var key in {a: 1, b: 2}) {
    alert(key); // a; b
}


Python:

for key in {'a': 1, 'b': 2}:
    print(key); # a, b


Вы правильно трактуйте подачу, а не неадекватно ;) Расслабьтесь, это всего лишь форум.

В Питоне, for ... in итерирует и словари (равно, как и в JS объекты) и списки (равно, как и в JS - массивы). Сейчас картина прояснилась?

Что-то осталось недопонятым?

hogart 13.08.2009 18:58

Цитата:

Сообщение от Dmitry A. Soshnikov
В Питоне, for ... in итерирует и словари (равно, как и в JS объекты) и списки (равно, как и в JS - массивы).

Не соглашусь. В приведенном вами коде хорошо видно, что итерация идет по списку, элементами которого являются ключи словаря:)

Мне непонятны две вещи.
* Почему я почти не слышу других мнений, кроме вашего;
* Зачем вы меня убеждаете итерировать массив for..in'ом?:)


Часовой пояс GMT +3, время: 06:01.