ilyachalov (ilyachalov) wrote,
ilyachalov
ilyachalov

Category:

Учебник по JavaScript, ч.1: Разное

Прочел четырнадцатый раздел «Разное» первой части («Язык программирования JavaScript») учебника по JavaScript.

https://learn.javascript.ru

Часть 1. Язык программирования JavaScript (в т.ч. 93 подраздела)

Разделы:

14. Разное (6 подразделов)

14.1 Proxy и Reflect
14.2 Eval: выполнение строки кода
14.3 Каррирование
14.4 Побитовые операторы
14.5 BigInt
14.6 Intl: интернационализация в JavaScript

По подразделам 14.1 и 14.6 у меня есть отдельные посты:
1. JavaScript: объекты класса Proxy, решение задачи Observable
2. JavaScript: интернационализация, сортировка слов с Е и Ё

В подразделе 14.2 рассказано про встроенную функцию eval, позволяющую выполнять любой код, переданный этой функции в виде строки в первый параметр. Отмечено, что сегодня считается, что в использовании этой функции нет необходимости, в большинстве случаев ей есть лучшие альтернативы (по этому поводу можно почитать подраздел 6.7 «Синтаксис "new Function"» и раздел 13 «Модули» учебника). Более того, ее использование многие не одобряют, есть даже такая поговорка на английском: «eval is evil», что по-русски означает «eval — это зло».

В подразделе 14.3 рассмотрена техника для работы с функциями, которая называется «каррирование». Про это понятие в википедии есть отдельная статья:

https://ru.wikipedia.org/wiki/Каррирование

Мне эта статья не понравилась, так как там каррирование рассмотрено в основном с математической точки зрения и лично я ничего там не понял. Англоязычная статья написана гораздо понятнее и вообще она больше:

https://en.wikipedia.org/wiki/Currying

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

Так что же такое «каррирование»? Это процесс, трансформация. В результате каррирования (трансформации) из одной функции получают другую функцию, которая делает то же самое, но которую становится возможным применять в более удобном виде (ниже приведен пример для функции с тремя параметрами, но исходная функция может быть с любым числом параметров, большим одного; суть в том, что функция с несколькими параметрами трансформируется в функцию с одним параметром):
func(a, b, c) --> каррирование --> func(a)(b)(c)

Вид func(a)(b)(c) удобен не всегда, а только в некоторых случаях. Что это за случаи? Например, в нашей программе есть функция func(a, b, c) и она применяется очень часто. При этом, скажем, из десяти случаев применения этой функции в девяти случаях первый параметр a имеет одно и то же значение. При такой ситуации было бы удобно иметь функцию func_a, у которой только два параметра — b и c, а значение a задано в самой функции локально, раз уж оно остается неизменным. Тогда в одном случае из десяти применяем функцию func(a, b, c), а в девяти случаях из десяти применяем функцию func_a(b, c). Это может сделать код более читабельным и понятным.

Еще пример. Та же ситуация, только теперь в одном случае из десяти удобно применить функцию func(a, b, c), в четырех из десяти — функцию func_a(b, c), а в пяти из десяти — функцию func_ab(c) (то есть в этом случае параметры a и b остаются неизменными, а меняется только третий параметр c). Что тут делать программисту? Можно написать три функции func(a, b, c), func_a(b, c) и func_ab(c), но они будут делать одно и то же, а один из общеизвестных принципов хорошего программирования — в программе не должно быть дублирующего кода!

Один из способов решить эту проблему — каррирование. Мы пишем только функцию func(a, b, c), а затем каррируем ее. Теперь можно делать следующее (это псевдокод):
function func(a, b, c) {         // пишем функцию
    // ... тело функции ...
}

func = каррирующаяФункция(func); // каррируем ее

let func_a = func(a);            // получаем функцию func_a

let func_ab = func_a(b);         // получаем функцию func_ab

// Далее можно применять в нужных случаях нужный вариант:
func(a, b, c);
func_a(b, c);
func_ab(c);
И вуаля! У нас появились три нужные функции и только одно тело функции! Каррирующую функцию можно написать самому, в подразделе 14.3 рассказано, как. Либо можно взять готовую из какой-нибудь библиотеки (в подразделе 14.3 в пример приводится каррирующая функция _.curry из библиотеки Lodash).

В программировании есть еще термин «частичное применение функции», родственный «каррированию»:
https://ru.wikipedia.org/wiki/Частичное_применение
https://en.wikipedia.org/wiki/Partial_application

В подразделе 14.4 рассказано про побитовые операторы, которые интерпретируют операнды как последовательность из 32 битов (нулей и единиц). Мне понравилось объяснение формата 32-битного целого со знаком. Еще мне понравилось, что рассказано про самые частые варианты применения побитовых операторов в программировании на языке JavaScript (в качестве маски, для округления чисел, для проверки на -1, для шифрования, для умножения и деления на степени двойки).

В подразделе 14.5 рассказано про один из базовых типов в языке JavaScript — BigInt. Это относительно новая возможность в языке. Ранее про этот тип данных уже рассказывалось в подразделе 2.5 «Типы данных» учебника.

Стоит отметить, что в англоязычной версии учебника отсутствуют подразделы 14.4 «Побитовые операторы» и 14.6 «Intl: интернационализация в JavaScript». Зато там есть раздел 14.4 «Reference Type», которого нет в русскоязычной версии учебника.

Но не надо думать, что читатель русскоязычной версии что-то пропустит, потому что в русскоязычной версии содержание англоязычного подраздела 14.4 «Reference Type» дословно (на русском языке) вставлено в подраздел 4.4 «Методы объекта, "this"»:

https://learn.javascript.ru/object-methods#vnutrennyaya-realizatsiya-ssylochnyy-tip

О чем там речь? Там рассказано об ошибках, возникающих при потере контекста «this» (об этом также можно почитать и в подразделе 6.10 «Привязка контекста к функции»), почему эти ошибки происходят. Рассказано про внутренний тип для языка JavaScript — «ссылочный тип» (по-английски «Reference Type»), этот тип программист не может использовать, он предназначен для внутреннего использования движком языка.
Tags: Образование, Программирование
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments