Что такое iife js
Вызов функции на месте в JavaScript
Давайте посмотрим на примере. Пусть у нас есть вот такое функциональное выражение:
Давайте теперь не будем присваивать нашу функцию в переменную, а вызовем ее сразу же, «на месте». Для этого после функции поставим круглые скобки:
Определите, не запуская код, что выведется на экран:
Определите, не запуская код, что выведется на экран:
Присваивание в переменную
Пусть теперь наша вызываемая на месте функция не выводит что-то алертом на экран, а возвращает через return :
Давайте присвоим результат работы нашей функции в переменную и выведем его на экран:
Так как в данном случае идет присваивание в переменную, то плюс уже не нужен.
Определите, не запуская код, что выведется на экран:
Определите, не запуская код, что выведется на экран:
Определите, не запуская код, что выведется на экран:
Применение вызова на месте
Давайте применим вызов функции на месте в качестве одного из слагаемых:
Определите, не запуская код, что выведется на экран:
Круглые скобки
Обычно при вызове функции на месте вместо плюса используются круглые скобки, так как такой способ оформления считается более очевидным:
Чаще всего круглые скобки вызова функции ставят снаружи, вот так:
Определите, не запуская код, что выведется на экран:
Определите, не запуская код, что выведется на экран:
Определите, не запуская код, что выведется на экран:
Определите, не запуская код, что выведется на экран:
Параметры
Пусть наша функция, которую мы собираемся вызывать на месте, параметром принимает строку для вывода алертом:
Давайте вызовем нашу функцию на месте, передав ей строку для вывода на экран:
Определите, не запуская код, что выведется на экран:
Несколько скобок
Пусть вам предложат хитрую задачу: сделать несколько вызывающих скобок, вот так:
Если поразмыслить, то становится очевидно, что в данном случае вызов функции на месте должен возвращать анонимную функцию, вот так:
Допишите следующий код так, чтобы его запуск алертом выводил ‘!’ :
Допишите следующий код так, чтобы его запуск выводил сумму переданных параметрами чисел:
Допишите следующий код так, чтобы его запуск выводил сумму переданных параметрами чисел:
Подводные камни
Давайте рассмотрим два кусочка кода.
Вы можете спросить: как же так, ведь в JavaScript точка с запятой в конце команды не является обязательной! На самом деле это не совсем так. Давайте разберемся, что у нас на самом деле происходит.
Первый код можно переписать вот так:
Если же после единицы поставить точку с запятой, то код будет воспринят интерпретатором по-другому:
То есть присваивание в переменную и вызов функции на месте станут разными командами. И все из-за наличия точки с запятой!
Давайте тогда разберемся, а почему мы вообще можем не писать точку с запятой в JavaScript. Пусть у нас есть такой код без точек с запятыми:
Он работает корректно, так как интерпретатор сам расставил в конце каждой строки точку с запятой.
Но посмотрите на такой код:
Получается, что интерпретатор сам ставит точку с запятой, только если следующая команда не является частью предыдущей.
А теперь посмотрите на этот код:
Это говорит о том, что лучше всего всегда ставить точку с запятой в нужных местах, во избежание проблем.
Точка с запятой для безопасности
Пусть теперь наша вызывающаяся на месте функция будет не с плюсом в начале, а обернута круглыми скобками, вот так:
Пусть переменная num задается снаружи функции:
Пусть теперь мы забыли поставить точку с запятой:
Получается, что такой код выдаст ошибку, так как JavaScript воспринимает нашу функцию как продолжение команды первой строки.
Чтобы избежать таких проблем, перед вызовом функции на месте всегда необходимо ставить точку с запятой, вот так:
Кажется, что проблема несколько надуманна. На самом деле, это не так. Может быть такая ситуация, что у вас на странице подключаются несколько скриптов из отдельный файлов. В этом случае в конце одного файла может быть опущена точка с запятой и это автоматически приведет к проблеме, если второй файл начинается с вызова функции на месте.
Поэтому, всегда-всегда ставьте точку с запятой перед вызовом функции на месте, даже если вы на данный момент уверены, что проблем не будет. Они могут возникнуть потом.
Применим сказанное выше и вызовем функцию на месте, поставив в начале точку с запятой:
Определите, не запуская код, что выведется на экран:
Определите, не запуская код, что выведется на экран:
JS Замыкание и IIFE
В этой части учебника мы разберём что такое функция замыкания в javascript и в целом что такое это замыкание, также не много затроним IIFE.
Для чего нужны функция замыкания в JS:
Замыкания в JS нужны для безопасности, чтобы это понять, давайте покажу не большой пример:
Это очень короткий, но наглядный пример, в начале мы создаём переменную которую будем увеличивать, дальше идёт функция, которая как раз и увеличивает x, вызываем её несколько раз.
Вот что должно появиться в консоли:
Как видите всё правильно, но есть проблема, если мы решим изменить переменную x на слово «Hello», то программа уже не будет работать.
Как видите после единицы выводиться «NaN», а теперь представьте что программа более сложная, и от значения одной такой переменной будет зависеть вся работоспособность программы, чтобы избежать этого были придуманы замыкания.
Работа со замыканиями в JS:
Теперь разберём как сделать замыкание, для этого на JS покажу простой пример замыкания:
Она выведет всё тоже самое что и первый пример, но теперь её нельзя так просто взять и сломать, давайте разберём в чём разница.
После получается мы присваиваем эту функцию переменной, и вызываем её три раза.
Таким образом мы её замкнули в определённой области видимости, и теперь не каких подобных проблем с безопасностью не должно быть.
IIFE JS:
Последние что стоит разобрать, так это что такое IIFE в JavaScript, это сокрушение от «immediately-invoked function expressions» или на русском означает функцию, запускаемую сразу после объявления.
То есть как понятно из названия, IIFE запускает функцию сразу после объявления.
Но на данный момент этот синтаксис редко используется, единственное, может ради конфигурации, чтобы они сразу применились, вот и всё.
Понимание (всех) «модульных» форматов и инструментов JavaScript
Доброго времени суток, друзья!
Представляю вашему вниманию перевод статьи «Understanding (all) JavaScript module formats and tools» автора Dixin.
При создании приложения часто возникает желание разделить код на части, логические или функциональные блоки (модули). Однако JavaScript изначально не имел поддержки модулей. Это привело к появлению различных модульных технологий. В настоящей статье обсуждаются все основные понятия, шаблоны, библиотеки, синтаксис и инструменты для работы с модулями в JavaScript.
IIFE модуль: шаблон JS модуля
Определяя переменную в JS, мы определяем ее как глобальную переменную. Это означает, что такая переменная будет доступна во всех файлах JS, загружаемых на текущей странице:
Для того, чтобы избежать загрязнения глобального пространства имен, можно использовать анонимную функцию:
Вуаля, глобальных переменных больше нет. Однако код внутри функции не выполняется.
IIFE: немедленно вызываемое функциональное выражение
Это называется IIFE (немедленно вызываемым функциональным выражением). Модуль может быть определен следующим образом:
Мы оборачиваем код модуля в IIFE. Анонимная функция возвращает объект. Это заменяет интерфейс экспорта. Присутствует только одна глобальная переменная — название модуля (или его пространство имен). Впоследствии название модуля может использоваться для его вызова (экспорта). Это называется шаблоном JS модуля.
Примеси импорта
При определении модуля могут потребоваться некоторые зависимости. При использовании модульного шаблона каждый зависимый модуль — глобальная переменная. Зависимые модули могут определяться внутри анонимной функции или передаваться ей в качестве аргументов:
Ранние версии популярных библиотек, таких как jQuery, использовали этот шаблон (в последней версии jQuery используется UMD модуль).
Открытый модуль: шаблон открытого JS модуля
Шаблон открытого модуля был придуман Christian Heilmann. Этот шаблон также является IIFE, но акцент в нем делается на определении всех интерфейсов как локальных переменных внутри анонимной функции:
Такой синтаксис облегчает понимание того, за что отвечает (или что делает) каждый интерфейс.
CJS модуль: CommonJS модуль или Node.js модуль
CommonJS, первоначально названный ServerJS, это шаблон для определения и использования модулей. Он встроен в Node.js. По умолчанию каждый JS файл — это CJS. Переменные module и exports обеспечивают экспорт модуля (файла). Функция require обеспечивает загрузку и использование модуля. Следующий код демонстрирует определение модуля счетчика на синтаксисе CommonJS:
Вот как этот модуль используется:
В среде выполнения (движке) Node.js этот шаблон используется путем оборачивания кода внутри файла в функцию, которой в качестве параметров передаются переменные exports, module и функция require :
AMD модуль или RequireJS модуль
AMD (асинхронное определение модуля) — это шаблон для определения и использования модулей. Он используется в библиотеке RequireJS. AMD содержит функцию define для определения модуля, которая принимает название модуля, названия зависимостей и фабричную функцию:
Он также содержит функцию require для использования модуля:
require AMD отличается от require CommonJS тем, что в качестве аргументов функции принимает названия модулей и сами модули.
Динамическая загрузка
Функция define также имеет другое назначение. Она принимает функцию обратного вызова и передает похожую на CommonJS require этой функции. Внутри функции обратного вызова require вызывается для динамической загрузки модуля:
AMD модуль из CommonJS модуля
UMD модуль: универсальное определение модуля или UmdJS модуль
UMD (универсальное определение модуля) — набор шаблонов для обеспечения работы модуля в разных средах выполнения.
UMD для AMD (RequireJS) и браузера
Следующий код обеспечивает работу модуля как в AMD (RequireJS), так и в браузере:
Выглядит сложно, но это всего лишь IIFE. Анонимная функция определяет наличие функции define из AMD/RequireJS.
UMD для AMD (RequireJS) и CommonJS (Node.js)
Следующий код обеспечивает работу модуля как в AMD (RequireJS), так и в CommonJS (Node.js):
Не пугайтесь, это снова всего лишь IIFE. При вызове анонимной функции, происходит «оценка» ее аргумента. Оценивание аргумента позволяет определить среду выполнения (определяется наличие переменных module и exports из CommonJS/Node.js, а также функции define из AMD/RequireJS).
ES модуль: ECMAScript2015 или ES6 модуль
Для обратной совместимости в браузере можно добавить тег
ES динамический модуль: ECMAScript2020 или ES11 динамический модуль
В последней 11 версии спецификации JS 2020 года представлена встроенная функция import для динамического использования ES модулей. Данная функция возвращает промис, поэтому использовать модуль можно с помощью then :
Благодаря тому, что функция import возвращает промис, в ней может использоваться ключевое слово await :
Системный модуль: SystemJS модуль
SystemJS — это библиотека для обеспечения работы ES модулей в старых браузерах. Например, следующий модуль написан с использованием синтаксиса ES6:
Этот код не будет работать в браузерах, не поддерживающих синтаксис ES6. Одним из решений данной проблемы является транспиляция кода с помощью интерфейса System.register библиотеки SystemJS:
Нового модульного синтаксиса ES6 больше нет. Зато код будет прекрасно работать в старых браузерах. Эта транспиляция может быть выполнена автоматически с помощью Webpack, TypeScript и т.д.
Динамическая загрузка модуля
SystemJS также содержит функцию import для динамического импорта:
Webpack модуль: транспиляция и сборка CJS, AMD и ES модулей
Webpack — это сборщик модулей. Его транспилятор объединяет CommonJS, AMD и ES модули в единый сбалансированный модульный шаблон и собирает весь код в один файл. Например, в следующих 3 файлах определяются 3 модуля с помощью различного синтаксиса:
Следующий код демонстрирует использование этого модуля:
Webpack способен объединить эти файлы, несмотря на то, что они представляют собой разные модульные системы, в один файл main.js :
Поскольку Webpack основан на Node.js, он использует модульный синтаксис CommonJS. В webpack.config.js :
Для транспиляции и сборки необходимо выполнить следующие команды:
И снова это всего лишь IIFE. Код из 4 файлов преобразован в массив из 4 функций. И этот массив передается анонимной функции в качестве параметра.
Babel модуль: транспиляция ES модуля
Babel — это еще один транспилятор для обеспечения работы ES6+ кода в старых браузерах. Приведенный выше ES6+ модуль может быть преобразован в Babel модуль следуюшим образом:
Это транспиляция по умолчанию. Babel также умеет работать с другими инструментами.
Babel и SystemJS
SystemJS может использоваться как плагин для Babel:
Данный плагин должен быть добавлен в babel.config.json :
Теперь Babel может работать с SystemJS для транспиляции CommonJS/Node.js, AMD/RequireJS и ES модулей:
Весь синтаксис AMD, CommonJS и ES модулей транспилирован в синтаксис SystemJS:
TypeScript модуль: транспиляция CJS, AMD, ES и SystemJS модулей
TypeScript поддерживает все разновидности синтаксиса JS, включая ES6. При транспиляции синтаксис ES6 модуля может быть сохранен или преобразован в другой формат, в том числе CommonJS/Node.js, AMD/RequireJS, UMD/UmdJS или SystemJS согласно настройкам транспиляции в tsconfig.json :
Модульный синтаксис ES, поддерживаемый TypeScript, получил название внешних модулей.
Внутренние модули и пространство имен
Оба транспилируются в JS объекты:
Sub module и sub namespace транспилируются в свойства объекта:
TypeScript module и namespace также могут использоваться в операторе export :
Приведенный код также транспилируется в sub module и sub namespace:
Заключение
Добро пожаловать в JS, который имеет 10+ систем/форматов модуляции/пространства имен:
Спасибо за потраченное время. Надеюсь, оно было потрачено не зря.
Руководство по JavaScript, часть 4: функции
Сегодня публикуем четвёртую часть перевода руководства по JavaScript, которая посвящена функциям.
Функции в JavaScript
Поговорим о функциях в JavaScript, сделаем их общий обзор и рассмотрим подробности о них, знание которых позволит вам эффективно ими пользоваться.
Функция — это самостоятельный блок кода, который можно, один раз объявив, вызывать столько раз, сколько нужно. Функция может, хотя это и необязательно, принимать параметры. Функции возвращают единственное значение.
Кроме того, функции в JavaScript называют «функциями первого класса» так как их можно назначать переменным, их можно передавать другим функциям в качестве аргументов, их можно возвращать из других функций.
Сначала рассмотрим особенности работы с функциями и соответствующие синтаксические конструкции, которые существовали в языке до появления стандарта ES6 и актуальны до сих пор.
Вот как выглядит объявление функции (function declaration).
В наши дни такие функции называют «обычными», отличая их от «стрелочных» функций, которые появились в ES6.
Функцию можно назначить переменной или константе. Такая конструкция называется функциональным выражением (function expression).
Можно заметить, что в вышеприведённом примере функция назначена константе, но сама она имени не имеет. Такие функции называют анонимными. Подобным функциям можно назначать имена. В таком случае речь идёт об именованном функциональном выражении (named function expression).
Использование таких выражений повышает удобство отладки (в сообщениях об ошибках, где проводится трассировка стека, видно имя функции). Имя функции в функциональном выражении может понадобиться и для того, чтобы функция могла бы сама себя вызывать, без чего не обойтись при реализации рекурсивных алгоритмов.
В стандарте ES6 появились стрелочные функции (arrow function), которые особенно удобно использовать в виде так называемых «встроенных функций» (inline function) — в роли аргументов, передаваемых другим функциям (коллбэков).
Стрелочные функции, помимо того, что структуры, используемые для их объявления, получаются более компактными, чем при использовании обычных функций, отличаются от них некоторыми важными особенностями, о которых мы поговорим ниже.
Параметры функций
Параметры представляют собой переменные, которые задаются на этапе объявления функции и будут содержать передаваемые ей значения (эти значения называют аргументами). Функции в JavaScript могут либо не иметь параметров, либо иметь один или несколько параметров.
Здесь показано несколько примеров стрелочных функций.
Начиная со стандарта ES6 у функций могут быть так называемые «параметры по умолчанию» (default parameters).
Они представляют собой стандартные значения, задаваемые параметрам функций в том случае, если при её вызове значения некоторых параметров не задаются. Например, функцию, показанную выше, можно вызвать как с передачей ей всех двух принимаемых ей параметров, так и другими способами.
В ES8 появилась возможность ставить запятую после последнего аргумента функции (это называется trailing comma). Эта возможность позволяет повысить удобство редактирования кода при использовании систем контроля версий в ходе разработки программ. Подробности об этом можно почитать здесь и здесь.
Передаваемые функциям аргументы можно представлять в виде массивов. Для того чтобы разобрать эти аргументы можно воспользоваться оператором, который выглядит как три точки (это — так называемый «оператор расширения» или «оператор spread»). Вот как это выглядит.
Если функции нужно принимать много параметров, то запомнить порядок их следования может быть непросто. В таких случаях используются объекты с параметрами и возможности по деструктурированию объектов ES6.
Этот приём позволяет, описывая параметры в виде свойств объекта и передавая функции объект, получить в функции доступ к параметрам по их именам без использования дополнительных конструкций. Подробнее об этом приёме можно почитать здесь.
Значения, возвращаемые из функций
Если после ключевого слова return указать некое значение, то это значение возвращается в место вызова функции в качестве результата выполнения этой функции.
Из функции можно возвращать лишь одно значение. Для того чтобы получить возможность возврата нескольких значений, возвращать их можно либо в виде объекта, используя объектный литерал, либо в виде массива, а при вызове функции применять конструкцию деструктурирующего присваивания. Имена параметров при этом сохраняются. При этом, если нужно работать с объектом или массивом, возвращённым из функции, именно в виде объекта или массива, можно обойтись без деструктурирующего присваивания.
Конструкцию const [ name, age ] = doSomething() можно прочитать следующим образом: «объявить константы name и age и присвоить им значения элементов массива, который возвратит функция».
Вот как то же самое выглядит с использованием объекта.
Вложенные функции
Функции можно объявлять внутри других функций.
Область видимости вложенной функции ограничена внешней по отношению к ней функцией, её нельзя вызвать извне.
Методы объектов
Когда функции используются в качестве свойств объектов, такие функции называют методами объектов.
Ключевое слово this
Как видно, вызов метода start() приводит ко вполне ожидаемому результату, а вот метод stop() явно работает неправильно.
Вот как выглядит выполнение такого кода в консоли браузера.
Особенности ключевого слова this в обычных и стрелочных функциях
Всё это означает, что стрелочные функции не подходят на роль методов объектов и конструкторов (если попытаться использовать стрелочную функцию в роли конструктора — будет выдана ошибка TypeError ).
Немедленно вызываемые функциональные выражения
Немедленно вызываемое функциональное выражение (Immediately Invoked Function Expression, IIFE) — это функция, которая автоматически вызывается сразу после её объявления.
Точка с запятой перед IIFE необязательна, но её использование позволяет застраховаться от ошибок, связанных с автоматической расстановкой точек с запятой.
Поднятие функций
Если переместить вызов функции так, чтобы он шёл после её объявления, ничего не изменится.
Если же в похожей ситуации воспользоваться функциональным выражением, то похожий код выдаст ошибку.
Стрелочные функции
Сейчас мы подробнее поговорим о стрелочных функциях, с которыми мы уже встречались. Их можно считать одним из наиболее значительных новшеств стандарта ES6, они отличаются от обычных функций не только внешним видом, но и особенностями поведения. В наши дни они используются чрезвычайно широко. Пожалуй, нет ни одного современного проекта, где они не использовались бы в подавляющем большинстве случаев. Можно сказать, что их появление навсегда изменило и внешний вид JS-кода и особенности его работы.
С чисто внешней точки зрения синтаксис объявления стрелочных функций оказывается компактнее синтаксиса обычных функций. Вот объявление обычной функции.
Вот объявление стрелочной функции, которое, в целом, если не учитывать особенности стрелочных функций, аналогично предыдущему.
Как видите, параметры стрелочных функций, как и в случае с обычными функциями, описывают в скобках. При этом, если такая функция принимает всего один параметр, его можно указать без скобок. Например, вот функция, которая возвращает результат деления переданного ей числа на 2.
В результате оказывается, что стрелочные функции очень удобно использовать в ситуациях, в которых нужны маленькие функции.
▍Неявный возврат результатов работы функции
Мы уже касались этой особенности стрелочных функций, но она настолько важна, что её следует обсудить подробнее. Речь идёт о том, что однострочные стрелочные функции поддерживают неявный возврат результатов своей работы. Пример возврата примитивного значения из однострочной стрелочной функции мы уже видели. Как быть, если такая функция должна возвратить объект? В таком случае фигурные скобки объектного литерала могут запутать систему, поэтому в теле функции используются круглые скобки.
▍Ключевое слово this и стрелочные функции
Как мы уже видели, при использовании ключевого слова this в методе объекта, представленного обычной функцией, this указывает на объект, которому принадлежит метод. В таком случае говорят о привязке ключевого слова this к значению, представляющему собой контекст выполнения функции. В частности, если функция вызвана в виде метода объекта, то ключевое слово this привязано к этому объекту.
В случае же со стрелочными функциями оказывается так, что в них привязка this не выполняется, они пользуются ключевым словом this из содержащих их областей видимости. В результате их не рекомендуется использовать в качестве методов объектов.
Замыкания
Замыкания — это важная концепция в JavaScript. Фактически, если вы писали JS-функции, то вы пользовались и замыканиями. Замыкания применяются в некоторых паттернах проектирования — в том случае, если нужно организовать строгий контроль доступа к неким данным или функциям.
Когда функция вызывается, у неё есть доступ ко всему тому, что находится во внешней по отношению к ней области видимости. Но к тому, что объявлено внутри функции, извне доступа нет. То есть, если в функции была объявлена некая переменная (или другая функция), они недоступны внешнему коду ни во время выполнения функции, ни после завершения её работы. Однако если из функции возвратить другую функцию, то эта новая функция будет иметь доступ ко всему тому, что было объявлено в исходной функции. При этом всё это будет скрыто от внешнего кода в замыкании.
Рассмотрим пример. Вот функция, которая принимает имя собаки, после чего выводит его в консоль.
Значение, возвращаемое этой функцией нас пока не интересует, текст выводится в консоль с помощью IIFE, что в данном случае особой роли не играет, однако, это поможет нам увидеть связь между этой функцией и её вариантом, в котором, вместо вызова функции, которая выводит текст в консоль, мы эту функцию из переписанной функции bark() возвратим.
Результат работы код в двух случаях оказывается одинаковым. Но во втором случае то, что было передано исходной функции при её вызове (имя собаки, Roger ), хранится в замыкании, после чего используется другой функцией, возвращённой из исходной.
Проведём ещё один эксперимент — создадим, пользуясь исходной функцией, две новых, для разных собак.
Этот код выведет следующее.
Итоги
Уважаемые читатели! Как вы относитесь к стрелочным функциям в JavaScript?