Если вы похожи на меня, вы понимаете основы функций JS и знаете, как использовать их, чтобы помочь вам создавать свои программы, но в них есть сложности, которые вы проигнорировали, когда развиваете свои навыки работы с причудливыми фреймворками, библиотеками и т. Д. языки и технологии.

Но я собираюсь кратко проинформировать вас о том, что вам нужно знать, чтобы вы могли чувствовать себя более уверенными в JS-функциях.

Давай перейдем к делу.

Выражения, значения, утверждения, декларации, о мой

Чтобы легко понять функции, полезно разобраться в некоторых терминах.

Заявления - это блоки кода, которые могут быть выполнены:

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

Если JS может интерпретировать что-то как утверждение или выражение, если оно находится между (), тогда JS интерпретирует то, что находится внутри этого, как выражение (если возможно).

Объявления функций

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

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

Таким образом, они поднимаются, как и переменные, но обрабатываются по-другому. Объявления функций поднимаются вместе с их содержимым и оцениваются наверху своей области видимости, как если бы они были выражениями, которые были сохранены в переменной, названной в ее честь.

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

Функциональные выражения

Немного необычно, что функция действует как оператор. Более логичная роль функций также является наиболее распространенной. Большинство форм функций можно рассматривать как значения - вещи, которые могут быть полезны где-то еще. Они представляют собой набор инструкций, которым нужно следовать при вызове, и их можно сохранять и извлекать так же, как кулинарную книгу можно хранить на книжной полке (и рецептам которой можно следовать позже).

Выражения функций не поднимаются так же, как операторы функций.

Если вы знаете, как JS поднимает переменные и их присваивания, это не должно вас удивлять: присваивания поднимаемым объявлениям никогда не происходят до тех пор, пока они не присвоены строке.

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

Итак… стрелочные функции, функции обратного вызова, функции генератора, IIFE?

Независимо от того, какой тип функции вы используете в JS, это либо выражение функции, либо объявление / инструкция функции. Примириться со стрелочными функциями и функциями обратного вызова будет легче, если вы заметите, что независимо от того, через какие сумасшедшие синтаксические обручи они прыгают, все они делают более или менее одно и то же: либо это значение, которое передается куда-то еще, либо декларация, которая регистрируется и ожидает использования.

Функции обратного вызова

Функции обратного вызова не являются особым типом функций в JS или любом другом языке программирования, если на то пошло. Функции обратного вызова - это функциональные выражения, переданные в качестве параметра другой функции.

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

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

doSomethingToNumber принимает два параметра: число и функцию. В приведенном выше примере мы передали выражения анонимной функции в вызов нашей функции.

Подводя итог функциям обратного вызова, они представляют собой функциональные выражения, которые передаются в качестве аргументов в другую функцию. Вот и все!

Выражения функции стрелки

Выражения стрелочной функции - это синтаксическая окраска того, что на самом деле является просто выражением анонимной функции. Анонимная функция - это функция, с которой не связано свойство name, но ее можно использовать в зависимости от того, для чего она была назначена.

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

Вот несколько практических правил:

Перед стрелкой:

Вам не нужно (), если у вас есть один параметр.

Вам понадобится (), если у вас нет параметров.

Вам понадобится (), если у вас более одного параметра.

После стрелки:

  1. Вам не нужно {}, если вы возвращаете результат одного выражения.
  2. Вам понадобится {}, если ваш функциональный блок содержит более одного оператора.
  3. Вам нужно использовать ключевое слово return, если вы используете {}, если хотите, чтобы ваша функция что-либо возвращала.

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

Примечание On this

this в JS - сложная тема, лучше для другой статьи. Однако одно хорошее практическое правило this в отношении функций таково (каламбур): использование ключевого слова function даст вам непротиворечивое this. Использование стрелочных функций даст вам this, который сохраняет значение this. окружающего контекста Короче говоря, пока что держитесь подальше от стрелочных функций, если вы полагаетесь на ключевое слово this для достижения целей функций, И вы ожидаете, что оно будет работать на основе объем, в котором вы его написали, а не объем, в котором он выполняется.

От MDN:

Выражение стрелочной функции… не имеет собственных привязок к ключевым словам this, arguments, super или new.target. Выражения стрелочных функций плохо подходят в качестве методов и не могут использоваться в качестве конструкторов.

По сути, если у вас есть какие-либо проблемы, спросите себя, требуется ли от вашего выражения функции стрелки делать больше, чем оно было сделано, особенно когда дело касается this.

Функции генератора

Функции генератора уникальны. Написание функции-генератора очень похоже на то, как вы пишете объявления и выражения функций (без стрелок), за исключением того, что вы используете * и yield, чтобы заставить их творить чудеса.

Принцип работы функций генератора очень специфичен. Сначала вы создаете функцию генератора. Затем вы вызываете эту функцию генератора, и она возвращает объект-итератор, чей метод .next() используется для отмены приостановки генератора и возвращает простой объект с двумя свойствами: value, полученный при последней остановке, и логическое значение с именем done, которое имеет значение false, если итератору нужно больше, или true, если больше нечего делать.

Вот простой пример:

Итак, что здесь происходит? Функция генератора определена в строке 1. Она вызывается в строке 9 и возвращает объект-итератор, который используется впоследствии. В строке 10 при вызове myGenerator.next() запускается генератор. Генератор запускает весь найденный код до тех пор, пока не найдет yield. Когда он находит первый yield, он приостанавливает выполнение функции и возвращает первый объект, который содержит полученное значение, и логическое значение, которое говорит, что функция не завершена.

Давайте посмотрим на некоторые из возможностей, которые у нас есть при использовании функций генератора:

Давайте пройдемся по тому, что здесь отличается. В этом случае allTheBells вызывается в строке 1 до того, как мы его определили, что показывает, что объявления функций генератора следуют тем же правилам подъема, которые мы определили ранее для объявлений функций. Эта функция генератора также принимает параметр с именем startingValue. Здесь это 10. Как и обычная функция, эта переменная создается в области видимости функции и может использоваться в функции генератора.

Обратите внимание на строки 4, 5 и 7, что вы можете получить любое выражение. Обратите внимание, что функции генератора могут запускать код между выходами. Вы можете думать о ключевом слове yield как о знаке остановки. Когда yield будет достигнут, он остановит функцию и вернет объект, значение которого является аргументом yield. Когда вызывается next next (), функция сначала возвращается к функции вместо предыдущей и возвращает значение, которое она оценивает. Если yield не используется в качестве выражения в другом операторе, он мало что делает, но все, что передается в следующую функцию, является тем, что оценивает предыдущий оператор yield. Прохождение строк 17 и 18 (а также 9 и 10) может помочь объяснить это.

Когда myGenerator.next() вызывается в строке 17, он возобновляет функцию allTheBells из строки 9. Ничего не передается в вызов .next(), и в функции нет ничего, что могло бы его принять, поэтому она продолжает выполнение функции до тех пор, пока не перейдет к следующему yield в строке 10. Он возвращает аргумент после yield, создавая объект со значением 100. Когда myGenerator.next() вызывается в строке 18, 5 передается в него. Это 5, переданное в вызов .next(), и есть то, что yield 100 оценивает, и поскольку это значение теперь полностью возвращено, console.log его может быть завершено, и 5 записывается в консоль. Вызов .next() также возвращает объект, который сообщает нам значение следующего yield. Но следующего yield нет, поэтому он возвращает объект, значение которого равно undefined, а для done установлено значение true.

Я нашел второй пример на этой странице хорошим упражнением, которое поможет мне понять эти функции. А пока оставим эту тему и перейдем к последней теме, которую мы рассмотрим в этой статье: IIFE.

IIFE

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

Вы можете задаться вопросом, в чем смысл использования IIFE. Одно из их прекрасных применений - управлять масштабом. Первая функция - engineOn - представляет собой IIFE и скромна по своим функциональным возможностям. Это не так много, поэтому может показаться, что использовать весь синтаксис бессмысленно. Тем не менее, мы можем увидеть кое-что интересное, если посмотрим на строку 8. При запуске мы получаем ReferenceError. Почему? IIFE создает область действия функции, и переменные, созданные в этой области, недоступны в областях за ее пределами.

С ES6 нам не нужно использовать IIFE для защиты наших прицелов, как показано в строках с 14 по 18. Мы можем получить такой же уровень ограничения области видимости, используя ключевое слово block и let.

Так чем же полезен IIFE? Что ж ... позвольте нам перейти к нашей последней теме.

Читаемость

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

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

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

Поздравления

Ты сделал это. Вы потратили время, чтобы коснуться всех возможностей JS-функций. Удачи с вашими проектами и приложениями! Помните: сделайте его читабельным!