Чому розширення прототипів DOM / вбудованих об'єктів є поганою ідеєю?


15

Я шукаю остаточну відповідь на те, чому розширення вбудованих прототипів настільки сильно розроблено у спільноті розробників JS. Я використовую рамку прототипу JS деякий час, і мені це [1,2,3].each(doStuff)здається набагато елегантнішим, ніж $.each([1,2,3], doStuff). Я знаю, що це створює "забруднення простору імен", але я не розумію, чому це вважається поганим. Чи є реальне зниження продуктивності, пов'язане з розширенням вбудованих прототипів? Спасибі!


1
Одна річ - це те, що for(var ... in ...)петлі збиваються з часу передачі функцій прототипу.
pimvdb

4
"сильно покараний", справді ?! добрий боже, чоловіче:] ти все гаразд?
піксельбобі

Відповіді:


12

Я пропоную вам прочитати цю статтю, яка, на мою думку, досить добре пояснює, чому розширення об’єктів є поганою ідеєю, що стосується і прототипу.

Підсумовуючи:

Відсутність специфікації

Експозиція "об'єктів-прототипів" не є частиною жодної специфікації. [...] Для того, щоб впровадження повністю відповідало рівню 2 DOM, немає необхідності виставляти ці глобальні об'єкти 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...inв JavaScript), тим самим викликаючи код, який покладається на їх нормальну поведінку порушувати?

В основному, це ті самі проблеми, що виникають при неправильному використанні глобальних змінних. Сам по собі, можливо, нічого поганого не відбувається. Але це відкриває вам неприємності, коли два нібито відокремлених фрагмента коду раптово наступають один на одного (і болісно налагоджувати, коли це відбувається).

Безумовно, 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.