Функции в JavaScript как часть выражения. Стрелочные функции
Статья, в которой рассмотрим ещё один способ создания функции - посредством выражения определения. Кроме этого разберём отличие этого способа объявления функции от традиционного.
В JavaScript создавать функцию кроме классического способа (Function Declaration) можно ещё посредством:
- Function Expression;
- Arrow Function.
Создание функции с использованием синтаксиса Function Expression
Function Expression - это объявление функции, которая является частью какого-либо выражения (например, присваивания).
const имя_функции = function(параметры) { // инструкции };
Например, создание функции sum
с использованием «классического» синтаксиса (Function Declaration) и Function Expression:
// Function Declaration function sum(num1, num2) { return num1 + num2; }; // Function Expression const sum = function(num1, num2) { return num1 + num2; };
Вызов функции, созданной через Function Expression, выполняется посредством указания имени переменной, содержащей эту функцию и круглых скобок, внутрь которых при необходимости можно передать аргументы.
//вызов функции с передачей её 2 аргументов (чисел 7 и 4) sum(7, 4);
При объявлении функции посредством Function Expression дополнительно указывать имя функции после ключевого слова function
не нужно.
Его имеет смысл использовать только в том случае, если вы хотите её вызвать внутри её кода. Т.е. создать рекурсию. Вызвать эту функцию по этому имени в другом месте нельзя.
const factorial = function factorialInner(num) { if (num <= 1) { return 1; } // использование factorialInner для вызова функции return factorialInner(num - 1) * num; }; // вызовем функцию factorial(5) и выведем её результат в консоль console.log(factorial(5)); // 120 // при попытке вызвать функцию по имени factorialInner получим ошибку console.log(factorialInner(5)); // Uncaught ReferenceError: factorialInner is not defined
В этом коде функция хранится в константе factorial
. Вызвать эту функцию внутри её коде можно с помощью имени factorialInner
. Но использовать factorialInner
вне тела этой функции нельзя, для этого необходимо использовать константу factorial
.
Но вызвать функцию внутри её тела можно также с помощью свойства arguments.callee
:
const factorial = function(num) { if (num <= 1) { return 1; } return arguments.callee(num - 1) * num; };
Самовызывающаяся функция (IIFE)
Самовызывающаяся функция или IIFE - это функция, которая вызывается сразу же как только до неё дойдет интерпретатор кода.
Она используется для создания закрытой области видимости, и применяется в паттерне «модуль».
Для создания самовызывающейся функции, её необходимо обернуть в круглые скобки, а затем её вызвать, т.е. разместить ещё скобки, передав в них при необходимости аргументы.
// num1 и num2 - параметры самовызывающейся функции // 7 и 4 - аргументы самовызывающейся функции (function (num1, num2) { console.log(num1 + num2); // 11 })(7, 4);
Паттерн «модуль»:
const userInfo = (function () { // имя пользователя по умолчанию let name = 'Аноним'; // возвращаем объект, состоящий из 2 функций return { getName: function () { return name; }, setName: function (newName) { name = newName; }, }; })(); console.log(userInfo.getName()); // 'Аноним' console.log(userInfo.setName('Дима')); // 'Дима' console.log(userInfo.getName()); // 'Дима' // обратиться напрямую к переменной name нельзя, только через «публичные» методы console.log(userInfo.name); // undefined
Стрелочные функции (arrow function)
Стрелочная функция (arrow function) - это современный синтаксис для создания функций, который появился с приходом ES6 (ES 2015). Он позволяет записать её более кратко по сравнению с синтаксисом Function Expression.
Базовый синтаксис стрелочной функции:
(argument1, argument2, ... argumentN) => { // тело функции }
Например, функция возвращающая среднее арифметическое двух чисел:
// Function Expression const average = function(num1, num2) { return (num1 + num2) / 2; } // Стрелочная функция const average = (num1, num2) => { return (num1 + num2) / 2; }
В этом примере мы создали стрелочную функцию с двумя параметрами num1
и num2
, которая вычисляет выражение (num1 + num2) / 2
и возвращает его результат.
Если стрелочная функция простая, т.е. она просто вычисляет выражение как в предыдущем примере, то её можно записать ещё короче:
const average = (num1, num2) => (num1 + num2) / 2;
Пример, в котором создадим стрелочную функцию, возвращающую массив определённой длины, заполненный случайными числами от 0 до 9.
const fillArr = (numElements) => { const arr = []; for (let i = 0; i < numElements; i++) { arr.push(parseInt(Math.random() * 10)); } return arr; }; // вызов функции fillArr console.log(fillArr(5)); // [1, 4, 6, 4, 9]
При создании стрелочной функции с одним параметром круглые скобки можно не указывать:
const fillArr = numElements => { ... };
Если стрелочная функция не имеет параметров, или их два и более, то круглые скобки в этом случае нужно писать обязательно:
// () - необходимо указывать при отсутствии параметров const result = numElements = () => { console.log('Привет, мир!'); }; result(); // 'Привет, мир!'
До появления стрелочных функций каждая функция имела свой this
(контекст в котором она выполнялась).
Например, в функции-конструкторе Timer
в setInterval
контекст this
указывал не на этот объект, а на window
, т.к. данная функция является его методом:
const Timer = function () { // здесь this - это ссылка на этот объект this.counter = 0; setInterval(function () { // здесь this - это window console.log(this.counter++); }, 1000); }; const timer1 = new Timer();
Чтобы в setInterval
нам получить ссылку на этот объект, нам приходилось сохранять её в другую переменную, например that
:
const Timer = function () { this.counter = 0; // сохраняем текущий контекст в that const that = this; setInterval(function () { // используем that, которая указывает на этот объект console.log(that.counter++); }, 1000); }; const timer1 = new Timer();
Стрелочная функция не содержит собственный контекст this
. Значение this
в стрелочной функции определяется снаружи, т.е. из окружающего её контекста.
const Timer = function () { // здесь this - это ссылка на этот объект this.counter = 0; setInterval(() => { // здесь this тоже указывает на этот контекст, т.к. берётся снаружи console.log(this.counter++); }, 1000); }; const timer1 = new Timer();
Стрелочные функции не имеет собственного объекта arguments
. В этом случае получить аргументы для которых не заведены параметры можно с помощью rest параметров:
// ...otherNums - rest парамтеры const sum = (...otherNums) => { let result = 0; for (let num of otherNums) { if (typeof num === 'number') { result += num; } } return result; }; console.log(sum(2, 5, -7, 11)); // 11
Отличия между различными способами объявления функций
Отличия между Function Declaration, Function Expression и Arrow Function:
Function Declaration | Function Expression | Arrow Function | |
---|---|---|---|
Вызов функции? | По имени, после которого нужно указать круглые скобки:
// объявление функции square function square(a) { return a * a; } // вызов функции square console.log(square(5)); // 25 |
По имени переменной, после которой следует указать круглые скобки:
// объявление функции square const square = function (a) { return a * a; }; // вызов функции square console.log(square(5)); // 25 |
По имени переменной, после которой следует указать круглые скобки:
// объявление функции square const square = a => a * a; }; // вызов функции square console.log(square(5)); // 25 |
Всплытие (hoisting)? | Функции Function Declaration всплывают (hoisting), их можно вызывать до объявления:
// вызываем функцию square до её объявления console.log(square(7)); // 49 function square(a) { return a * a; } |
Функции Function Expression нельзя использовать до объявления. Если функция сохранена в переменную, созданную с помощью ключевого слова var , то в этом случае поднимается только сама переменная. Если сохранить функцию в const или let , то и переменная в данном варианте всплывать не будет.
// ошибка при вызове функции console.log(square(7)); // Uncaught ReferenceError: Cannot access 'square' before initialization const square = function (a) { return a * a; }; При сохранении функции в переменную, объявленную с помощью ключевого слова var square; // на этом этапе переменная square имеет значение undefined console.log(square(7)); // Uncaught TypeError: square is not a function square = function (a) { return a * a; }; |
Поведение стрелочной функции аналогично Function Expression. |
Видимость функции вне блока в строгом режиме ('use strict' )? |
При использовании 'use strict' функция, объявленная как Function Declaration, будет видна только внутри блока, в котором она объявлена.'use strict'; if (true) { function sum(a, b, c) { return a + b + c; } console.log(sum(4, 5, 4)); // 13 } // произойдёт ошибка console.log(sum(4, 5, 4)); // Uncaught ReferenceError: sum is not defined |
В отличие от Function Declaration, доступ к функции можно получить вне блока, в котором она создана (но только, если она сохранена в переменную, созданную с помощью ключевого слова var ):
'use strict'; if (true) { var sum = function (a, b, c) { return a + b + c; }; console.log(sum(10, 20, 10)); } // имеем доступ к функции sum console.log(sum(4, 5, 4)); |
Поведение стрелочной функции аналогично Function Expression. |
Наваял, но не работает:
Подскажите, в чем ошибка? Как можно это выражение записать стрелочной функцией?
Спасибо.
Напишите функцию, которая будет принимать на вход строку с надписью для гравировки. На выход функция отдает стоимость для гравировки. Если строка пустая или равна undefined, то цена гравировки равна 0.
Запишите в переменную строку текста, которую нужно будет выгравировать.
Создайте функцию, принимающую в качестве аргумента строку.
Воспользуйтесь методом split, чтобы получить массив слов, по аналогии с примером ниже:
Предусмотрите универсальный способ расчета стоимости гравировки от количества слов. Мы не ограничиваем клиентов по длине надписи.
Верните в качестве результата работы вычисленную стоимость.
Выведите результат работы функции в консоль в формате:
Подарочная упаковка и гравировка: