До того, как я начал изучать Javascript, у меня был довольно ограниченный опыт программирования, и большую часть времени я проводил с Ruby. Я не собираюсь приукрашивать свои чувства к JS, это не Ruby; ему серьезно не хватает того сладкого синтаксического сахара, к которому я привык за последние несколько месяцев.
Если оставить в стороне резкие слова, в Javascript есть несколько действительно крутых функций, с которыми я не сталкивался, изучая Ruby, и легче проводить ассоциации с уже известными мне концепциями, чем изучать совершенно новые. Одной из самых интересных концепций, с которыми я столкнулся, были замыкания и обратные вызовы.
Перезвони мне, может быть
Для перебора массива в Ruby мы можем использовать перечисления, которые создают объект перечислителя, который затем превращается в блок.
Чтобы сделать то же самое с помощью JS, мы можем использовать ряд итераторов или функцию более высокого уровня в «классе» Array.prototype
, такую как Array.prototype.forEach
или Array.prototype.map
, которая принимает функцию обратного вызова.
Обратные вызовы похожи на блоки в Ruby, но на них можно ссылаться, а не помещать непосредственно в блок. Давайте посмотрим на сравнение рядом:
# ruby [].each { |element| element.methods } // javascript [].forEach(element => element.functions)
Редко можно увидеть код, фактически извлеченный из блока перечислителя в Ruby, однако это обычная практика с эквивалентом в Javascript. Как рубисты и объектно-ориентированные программисты, мы должны стремиться поддерживать разделение задач в наших методах, записывая небольшие, удобные в сопровождении методы в легко читаемых сегментах, которые «делают» одну вещь. Было приятно писать обратные вызовы в javascript из-за того, как легко заключить каждую функцию.
Вложения Javascript и блоки Ruby
Языки с функциями первого класса, такие как Javascript, позволяют сохранять функции как переменные, передавать их в качестве аргументов другим функциям и даже могут возвращать другие функции. Замыкание — это первоклассная функция со своими собственными переменными окружения.
Методы Ruby имеют мало общего, но блоки Ruby являются замыканиями. Так же как и процедуры (procs) и лямбда-выражения.
С Procs и Lambdas мы можем хранить блоки в переменных. Их можно создать и вызвать:
Проки ведут себя как блоки, но их можно хранить в переменных. Лямбды — это процедуры, которые ведут себя как методы. Какая разница? Процедуры, как и функции в JS, не будут выдавать ошибку ArgumentError, если в блок будет передано слишком много аргументов. Лямбда-выражения действуют как методы, в том смысле, что они выдают ошибку. Есть еще несколько технических отличий, которые не входят в тему этого поста (где-то там есть шутка о закрытии), но я уверен, что вы можете найти много литературы по этому поводу.
Теперь, когда нам удалось сохранить блок в переменной, давайте сделаем последнюю растяжку:
Это уже не совсем читабельно, но я полагаю, что это немного лучше передает намерение.
Что, если бы мы использовали Унарный & оператор?
Это больше походит на это.