Самостоятельные анонимные замыкания: JavaScript неполон?

18

Означает ли тот факт, что анонимные закрытия самоссылающихся функций настолько распространены в JavaScript, говорит о том, что JavaScript является неполной спецификацией? Мы видим так много из этого:

(function () { /* do cool stuff */ })();

и я полагаю, что все дело вкуса, но разве это не похоже на кучу, когда все, что вам нужно - это личное пространство имен? Не мог JavaScript реализовать пакеты и правильные классы?

Сравните с ActionScript 3, также основанным на ECMAScript, где вы получаете

package com.tomauger {
  import bar;
  class Foo {
     public function Foo(){
       // etc...
     }

     public function show(){
       // show stuff
     }

     public function hide(){
       // hide stuff
     }
     // etc...
  }
}

В отличие от сверток, которые мы выполняем в JavaScript (это из документации по разработке плагина jQuery ):

(function( $ ){

  var methods = {
    init : function( options ) { // THIS },
    show : function( ) { // IS   },
    hide : function( ) { // GOOD },
    update : function( content ) { // !!! }
  };

  $.fn.tooltip = function( method ) {

    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    

  };

})( jQuery );

Я ценю, что этот вопрос может легко перерасти в сплетню о предпочтениях и стилях программирования, но мне действительно очень любопытно услышать, как вы, опытные программисты, относитесь к этому и чувствуете ли вы его естественным, как изучение различных особенностей нового языка, или клудж как обходной путь к некоторым базовым компонентам языка программирования, которые просто не реализованы?

Том Оже
источник
22
"Не может JavaScript реализовать ... правильные классы?" У него уже есть правильные прототипы. Прототипы не уступают классам. Они разные. Люди пытались добавлять классы в JavaScript в разное время и были довольно неудачными.
Рейн Хенрикс
5
@Rein: И все же каким-то образом ActionScript справился с этим ...
Мейсон Уилер
8
@ Там нет "встроенных классов". Там нет такого понятия, как класс на языке прототипов . Вы продолжаете смешивать две парадигмы.
Рейн Хенрикс
1
Лично я нахожу функцию языка анонимных функций более гибкой, чем классы. Однако мне нравится функциональное программирование, в котором эта идиома распространена.
dietbuddha
1
Для других, здесь: brianodell.net/?page_id=516 - отличное пособие по JavaScript как языку-прототипу.
Том Оже

Ответы:

9

Я полагаю, что все дело вкуса, но разве это не похоже на кучу, когда все, что вам нужно, это личное пространство имен? Не мог JavaScript реализовать пакеты и правильные классы?

Большинство комментариев противоречат мифу о том, что «прототипы - это классы бедняков», поэтому я просто повторю, что ОО на основе прототипов ничем не уступает ОО на основе классов.

Другой момент: «Кладж, когда все, что вам нужно, это личное пространство имен». Вы можете быть удивлены, узнав, что Scheme использует один и тот же ключ для определения областей действия. Это не помешало стать архетипическим примером хорошо сделанной лексической оценки.

Конечно, в Схеме «клудж» скрыт за макросами ....

Хавьер
источник
1
Вы не представите никаких доказательств в подтверждение своего утверждения о том, что Схема является основным примером хорошо выполненной лексической области видимости или что это имеет какое-либо отношение к тому, как Схема использует функции для определения областей.
DeadMG
Не могу говорить о том, что Scheme является образцом, но один из примеров того, как со-создатель JS Брендан Эйч обсуждает Scheme, играющую роль в дизайне JS, здесь: readwrite.com/2011/07/22/javascript-was-no-accident
Эрик Реппен,
7

Прежде всего, пара вещей:

  1. Другой способ взглянуть на JavaScript - это 1 миллион и 1 вещь, которую вы можете сделать с помощью функции в качестве конструкции. Это все там, если вы ищете это. Это просто никогда не далеко от функции.

  2. Эта вещь создания плагина jQuery ужасна. Я понятия не имею, почему они защищают это. $ extensions должен быть материалом общего назначения, который уже довольно хорошо описан в методах $ build-me-a-complete-widget. Это инструмент нормализации DOM-API. Его использование лучше всего скрывать внутри ваших собственных объектов. Я не вижу привлекательности использования его в качестве полноценного хранилища пользовательского интерфейса библиотеки.

Пакеты в клиентской сети бессмысленны

Что лично мне не нравится в пакетах в клиентской сети, так это то, что мы притворяемся, что делаем то, чего на самом деле нет. В мире веб-форм Post .NET и ужасных вещей, которые никогда не панорамируются нашими друзьями на Java, я бы предпочел, чтобы кусок HTML со связанными ресурсами был тем, чем он является на самом деле. и не пытаться успокоить обучающихся разработчиков новых приложений для ОС, притворяясь, что это что-то другое. В JS в клиентской сети ничего не «импортируется», если не делать что-то ужасное с Ajax, которое работает в неведении о кешировании браузера, что, да, многие пытались сделать. Все, что имеет значение для браузера, это то, что он был загружен и интерпретирован или не был. У нас нет больше кода, спрятанного на клиенте, где-то доступном для использования «на всякий случай» по уважительным причинам. # 1 в том, что я только что описал зависимости плагинов и плагинов браузеров для веб-приложений, как явление, как правило, не сработало слишком хорошо. Мы хотим веб сейчас. Не после обновления Adobe или Sun в третий раз на этой неделе.

Язык имеет то, что ему нужно для структуры

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

Просто потому, что это популярно, не значит, что мы все делаем правильно

Теперь, когда вы видите это во всем клиентском веб-приложении:

(function(){
//lots of functions defined and fired and statement code here
})()

Проблема не в том, что нам не хватает инструментов для структурирования приложения, проблема в том, что люди не ценят структуру. Для одноразовых временных сайтов на 2-3 страницы в дизайнерском агентстве у меня действительно нет проблем с этим. Все становится уродливым, когда вам нужно создать что-то удобное в обслуживании, легко читаемое и легко изменяемое.

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

Но есть реализации JS с пакетами / модулями

Имейте в виду, что в Node.js, где такие вещи имеют больше смысла, у них есть модули. JS, предполагая, что мы можем избежать uber-config-hell, который преследует другие языки, является единственным в уравнении, и каждый исполняемый файл имеет свою собственную изолированную область видимости. Но на веб-странице ссылка на js-файл сама по себе является оператором импорта. Выполнение большего количества операций импорта на лету - просто пустая трата времени и ресурсов, поскольку получение ресурсов требует гораздо больше усилий, чем просто добавление ссылок на файлы по мере их необходимости, зная, что они будут кэшироваться в браузере, если они понадобятся другой странице. Поэтому мы пытаемся разделить глобальное пространство, выполняя что-либо, кроме создания фабрик объектов-адаптеров, таких как jQuery, или более традиционных объектов, которые охватывают большой набор задач в данном домене, занимая одно место в глобальном пространстве. Там'http://wiki.ecmascript.org/doku.php?id=harmony:modules

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

Однако тот факт, что мы МОЖЕМ делать такие вещи, потрясающий. Интенсивное использование - это признак того, что разработчики JS, возможно, все еще находятся на стадии становления, но это не зияющая дыра в языке для тех, кто не пытается навязать парадигму в клиентскую сеть, которая здесь просто не имеет смысла.

Эрик Реппен
источник
Для Down-Voter, не могли бы вы объяснить, почему? Когда кто-то так много пишет, я думаю, он заслуживает объяснения!
Songo
+1 хороший ответ, не уверен, почему голосовал раньше.
Фле
Потрясающая рецензия и отличная перспектива. Мне также нравится «просто потому, что это тропа, не значит, что это правильно». Я думаю, что моя проблема в том, что мне удобнее использовать более строгие языки, которые (IMO) помогают повысить эффективность разработки несколькими способами. JavaScript кажется действительно бесполезным, поскольку в нем не так много встроенных сдержек и противовесов: вы можете делать все, что захотите, поэтому из-за сложившейся ситуации существует множество идиом и практик. Трудно найти "правильный" способ приблизиться к вашей структуре кодирования. Хотя я согласен с тем, что для быстрых одноразовых рабочих мест это не большая проблема.
Том Ожер
1
ИМО, есть много вещей, которые вы можете сделать с большим количеством веревки, кроме как повеситься, и вы учитесь писать надежный код быстрее из-за случайных зависаний, которые случаются реже, когда вы развиваете лучшие привычки, но я не буду притворяться, что это для каждый или идеальный кандидат на каждую работу. Я подозреваю, что чем больше вы узнаете об этом, тем более терпимым вы найдете это. Я чувствую, что мне не хватает половины моего мозга, когда я пытаюсь делать что-то на языках без функций первого класса или таких гибких / изменяемых объектов, как у JS.
Эрик Реппен
4

Еще одна вещь, которую вам не хватает, это то, что javscript должен быть обратно совместимым. Если вы попытаетесь ввести синтаксис пакета, он может действительно сломать сеть несколькими безумными способами. Это было бы плохо! Даг Крокфорд говорил об этом в разные моменты и почему попытки добавить его провалились.

Захари К
источник
Неплохо подмечено. И все же ActionScript справился с этим, просто выпустив новую версию. При определении тега скрипта вы всегда могли указать версию JavaScript, поэтому «взлом» существующих сайтов не должен вызывать проблем.
Том Оже
1
На практике большинство тегов сценариев в сети не имеют номера версии. Если честно, я не уверен во всех проблемах по этому вопросу, но я знаю, что люди, которые думают об этом, решили, что это не выполнимо.
Захари К
1
@Tom: Adobe также имеет полный контроль над платформой Flash. Ни один объект не имеет полного контроля над всеми платформами JS. Кроме того, просто добавление номера версии для JS-скрипта в браузере означало бы, что вы либо не поддерживаете старые браузеры, либо должны написать два скрипта. Таким образом, это является проблемой.
Джереми Хейлер
2

Да, это клудж.

Многие люди говорят, что «прототипы не уступают классам». Я не согласен, но это вопрос предпочтений. Но это даже не настоящая проблема с JavaScript - проблема в том, что он изначально разрабатывался как быстрый и грязный язык сценариев для создания таких вещей, как анимированные кнопки. Еще в середине 90-х никто никогда не думал, что JavaScript попросят сделать некоторые сумасшедшие вещи, которые он делает сейчас.

Майк Баранчак
источник
6
Я не согласен, язык JavaScript на самом деле действительно потрясающий. Все проблемы начались с того, что он был объединен с недопустимым и несовместимым DOM.
Дин Хардинг
2
Какое это имеет отношение к прототипам?
Эрик Реппен
2

Анонимные самопризывающиеся функции больше похожи на модули, чем на классы. Раздражает, что по умолчанию для javascript является запуск в глобальной области видимости. Комитет, работающий над JS.next, серьезно рассматривает вопрос о добавлении модулей, чтобы вы не оставили свои локальные переменные в глобальной области видимости. К счастью, функции Javascript имеют такую ​​удобную семантику, что мы можем использовать анонимную функцию как частную область с относительной простотой.

Я вообще не понимаю, как классы действительно участвуют в обсуждении, за исключением того, что они являются концепцией верхнего уровня во многих языках. Было бы неплохо иметь более подходящую конструкцию модуля / пакета / «пожалуйста, дай мне локальную область видимости, поэтому я не оставляю мои переменные в глобальном окружении».

Шон Макмиллан
источник
1

Возможно, вы захотите взглянуть на ExtJS 3 и 4, где им удалось реализовать пространства имен достаточно хорошо.

- добавлено после -1

Суть в том, что все эти «свертки» можно скрыть и при этом иметь довольно дружественный код, например:

Ext.ns('com.tomauger');
Ext.Loader.load('bar.js'); //unfortunately filname needs to be used
MyNameSpace.Foo = {
   //...
}
MCHL
источник