Здравствуйте, kkh, Вы писали:
kkh>да, и Вы меня заинтриговали — а что такого можно делать в js, что нельзя в с#? Реально, интересно.
kkh>(Дело в том, что, как мне кажется, в c# можно делать почти всё. Единственное, о чём лично я "горевал" — это отсутствие макросов и работы с темплейтами, как в сях. Дженерики, всё-таки, меньше возможностей имеют, чем старые добрые темплейты, как ни крути. Но зато они и меньше возможностей запутать код дают
high-order functions (функции высшего порядка). Ну и "обобщенные" функции высшего порядка (название мое, в литературе вряд ли найдете. Это те функции, которые в системы типов вроде ML'евской и Haskell'ной не укладываются).
На пальцах. high-order functions — это всевозможные map, например. Т.е.
functiion map(fn, array) {
res = [];
for (var x in array)
res.push(fn(x));
return res;
}
function mapC(fn) {
return function(arr) {
return map(fn, arr);
};
}
Вот map и mapC — функции высшего поярдка. Они принимают функции и иногда возвращают их. mapC — каррированная версия map (ну вот так она выглядит в javascript). Чтобы проникнутся удобством high-order function я бы рекомендовал OCaml или какой-нибудь другой из семейства ML-языков посмотреть. Заодно проникнетесь духом функционального программирования.
Второе, "обобщенные" функции. Это страшные вещи, которые с arguments работают вместо списка параметров. Один из любимых (правда, на firefox-диалекте, на простом js параметры нужно бы из arguments разбирать):
function bindf(fn, ...args) {
return function(...args1) {
return fn.apply(null, asArray(args))
}
}
/// somewhere in a code
button1.addEventListener("click", bindf(navigateToPage, "abc"));
button2.addEventListener("click", bindf(navigateToPage, "def"));
button3.addEventListener("click", bindf(navigateToPage, "quit"));
/// another example
value1 = Reactive.variable(123)
value2 = Reactive.variable(321)
atanv = Reactive.apply(atan2, [value1, value2])
atanstr = str.rapply(null, [atanv])
setText.rapply(null, textField, atanstr)
Оба примера — вариации на реально и часто используемые библиотеки (там не совсем js, правда). Первое — биндинг функции к аргументам. В основном как раз для слушателей используется. Особенно для компонентов UI (для рендеринга какого-нибудь элемента в list, например). Там рендеринг элементов делается обычным методом (без классов) и слушатели удобнее прикручивать так, чем явно расписывать замыкание, вызов метода и т.п.
Второй пример — реактивное программирование. Внутренности не показаны (достаточно приличных пока нет для публики, хотя уже заказывали). Внутри — те же самые fn.apply(...) с обработкой аргументов. в примере atanv и atanstr автоматически изменяют значение при изменении value1 и value2. А еще в случае изменения вызывается setText(textField, atanstr.value()) (textField — не reactive). x.rapply(null, ...) == Reactive.apply(x, ...) — базовый как раз reactive а потом на него биндинг для функций делается. В UI оказалось очень удобно. А заодно оказалось, что в ui много функций, которые не имеют побочных эффектов (pure function) и зависят только от их входных параметров. Поэтому при желании их можно очень даже хорошо тестировать.
У вас в парадигмах примерно 2-2,5 видел (точно разные smalltalk и немного макросов в C++). Вам бы еще FP стоит посмотреть (тот же ML какой-нибудь, потом можно и Haskell).