Функции
Выбери формат для чтения
Загружаем конспект в формате docx
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Функции
Зачастую нам надо повторять одно и то же действие во многих частях программы.
Например, необходимо красиво вывести сообщение при приветствии посетителя, при выходе посетителя с сайта, ещё где-нибудь.
Чтобы не повторять один и тот же код во многих местах, придуманы функции. Функции являются основными «строительными блоками» программы.
Примеры встроенных функций вы уже видели – это alert(message), prompt(message, default) и confirm(question). Но можно создавать и свои.
Объявление функции
Для создания функций мы можем использовать объявление функции.
Пример объявления функции:
function showMessage() {
alert( 'Всем привет!' );
}
Вначале идёт ключевое слово function, после него имя функции, затем список параметров в круглых скобках через запятую (в вышеприведённом примере он пустой) и, наконец, код функции, также называемый «телом функции», внутри фигурных скобок.
function имя(параметры) {
...тело...
}
Наша новая функция может быть вызвана по её имени: showMessage().
Например:
function showMessage() {
alert( 'Всем привет!' );
}
showMessage();
showMessage();
Вызов showMessage() выполняет код функции. Здесь мы увидим сообщение дважды.
Этот пример явно демонстрирует одно из главных предназначений функций: избавление от дублирования кода.
Если понадобится поменять сообщение или способ его вывода – достаточно изменить его в одном месте: в функции, которая его выводит.
Локальные переменные
Переменные, объявленные внутри функции, видны только внутри этой функции.
Например:
function showMessage() {
let message = "Привет, я JavaScript!"; // локальная переменная
alert( message );
}
showMessage(); // Привет, я JavaScript!
alert( message ); // <-- будет ошибка, т.к. переменная видна только внутри функции
Внешние переменные
У функции есть доступ к внешним переменным, например:
let userName = 'Вася';
function showMessage() {
let message = 'Привет, ' + userName;
alert(message);
}
showMessage(); // Привет, Вася
Функция обладает полным доступом к внешним переменным и может изменять их значение.
Например:
let userName = 'Вася';
function showMessage() {
userName = "Петя"; // (1) изменяем значение внешней переменной
let message = 'Привет, ' + userName;
alert(message);
}
alert( userName ); // Вася перед вызовом функции
showMessage();
alert( userName ); // Петя, значение внешней переменной было изменено функцией
Внешняя переменная используется, только если внутри функции нет такой локальной.
Если одноимённая переменная объявляется внутри функции, тогда она перекрывает внешнюю. Например, в коде ниже функция использует локальную переменную userName. Внешняя будет проигнорирована:
let userName = 'Вася';
function showMessage() {
let userName = "Петя"; // объявляем локальную переменную
let message = 'Привет, ' + userName; // Петя
alert(message);
}
// функция создаст и будет использовать свою собственную локальную переменную userName
showMessage();
alert( userName ); // Вася, не изменилась, функция не трогала внешнюю переменную
Глобальные переменные
Переменные, объявленные снаружи всех функций, такие как внешняя переменная userName в вышеприведённом коде – называются глобальными.
Глобальные переменные видимы для любой функции (если только их не перекрывают одноимённые локальные переменные).
Желательно сводить использование глобальных переменных к минимуму. В современном коде обычно мало или совсем нет глобальных переменных. Хотя они иногда полезны для хранения важнейших «общепроектовых» данных.
Параметры
Мы можем передать внутрь функции любую информацию, используя параметры (также называемые аргументами функции).
В нижеприведённом примере функции передаются два параметра: from и text.
function showMessage(from, text) { // аргументы: from, text
alert(from + ': ' + text);
}
showMessage('Аня', 'Привет!'); // Аня: Привет! (*)
showMessage('Аня', "Как дела?"); // Аня: Как дела? (**)
Когда функция вызывается в строках (*) и (**), переданные значения копируются в локальные переменные from и text. Затем они используются в теле функции.
Вот ещё один пример: у нас есть переменная from, и мы передаём её функции. Обратите внимание: функция изменяет значение from, но это изменение не видно снаружи. Функция всегда получает только копию значения:
function showMessage(from, text) {
from = '*' + from + '*'; // немного украсим "from"
alert( from + ': ' + text );
}
let from = "Аня";
showMessage(from, "Привет"); // *Аня*: Привет
// значение "from" осталось прежним, функция изменила значение локальной переменной
alert( from ); // Аня
Параметры по умолчанию
Если параметр не указан, то его значением становится undefined.
Например, вышеупомянутая функция showMessage(from, text) может быть вызвана с одним аргументом:
showMessage("Аня");
Это не приведёт к ошибке. Такой вызов выведет "Аня: undefined". В вызове не указан параметр text, поэтому предполагается, что text === undefined.
Если мы хотим задать параметру text значение по умолчанию, мы должны указать его после =:
function showMessage(from, text = "текст не добавлен") {
alert( from + ": " + text );
}
showMessage("Аня"); // Аня: текст не добавлен
Теперь, если параметр text не указан, его значением будет "текст не добавлен"
В данном случае "текст не добавлен" это строка, но на её месте могло бы быть и более сложное выражение, которое бы вычислялось и присваивалось при отсутствии параметра. Например:
function showMessage(from, text = anotherFunction()) {
// anotherFunction() выполнится только если не передан text
// результатом будет значение text
}
Вычисление параметров по умолчанию
В JavaScript параметры по умолчанию вычисляются каждый раз, когда функция вызывается без соответствующего параметра.
В примере выше anotherFunction() будет вызываться каждый раз, когда showMessage() вызывается без параметра text.
Использование параметров по умолчанию в ранних версиях JavaScript
Ранние версии JavaScript не поддерживали параметры по умолчанию. Поэтому существуют альтернативные способы, которые могут встречаться в старых скриптах.
Например, явная проверка на undefined:
function showMessage(from, text) {
if (text === undefined) {
text = 'текст не добавлен';
}
alert( from + ": " + text );
}
…Или с помощью оператора ||:
function showMessage(from, text) {
// Если значение text ложно, тогда присвоить параметру text значение по умолчанию
text = text || 'текст не добавлен';
...
}
Возврат значения
Функция может вернуть результат, который будет передан в вызвавший её код.
Простейшим примером может служить функция сложения двух чисел:
function sum(a, b) {
return a + b;
}
let result = sum(1, 2);
alert( result ); // 3
Директива return может находиться в любом месте тела функции. Как только выполнение доходит до этого места, функция останавливается, и значение возвращается в вызвавший её код (присваивается переменной result выше).
Вызовов return может быть несколько, например:
function checkAge(age) {
if (age > 18) {
return true;
} else {
return confirm('А родители разрешили?');
}
}
let age = prompt('Сколько вам лет?', 18);
if ( checkAge(age) ) {
alert( 'Доступ получен' );
} else {
alert( 'Доступ закрыт' );
}
Возможно использовать return и без значения. Это приведёт к немедленному выходу из функции.
Например:
function showMovie(age) {
if ( !checkAge(age) ) {
return;
}
alert( "Вам показывается кино" ); // (*)
// ...
}
В коде выше, если checkAge(age) вернёт false, showMovie не выполнит alert.
Результат функции с пустым return или без него – undefined
Если функция не возвращает значения, это всё равно, как если бы она возвращала undefined:
function doNothing() { /* пусто */ }
alert( doNothing() === undefined ); // true
Пустой return аналогичен return undefined:
function doNothing() {
return;
}
alert( doNothing() === undefined ); // true
Никогда не добавляйте перевод строки между return и его значением
Для длинного выражения в return может быть заманчиво разместить его на нескольких отдельных строках, например так:
return
(some + long + expression + or + whatever * f(a) + f(b))
Код не выполнится, потому что интерпретатор JavaScript подставит точку с запятой после return. Для него это будет выглядеть так:
return;
(some + long + expression + or + whatever * f(a) + f(b))
Таким образом, это фактически стало пустым return.
Если мы хотим, чтобы возвращаемое выражение занимало несколько строк, нужно начать его на той же строке, что и return. Или, хотя бы, поставить там открывающую скобку, вот так:
return (
some + long + expression
+ or +
whatever * f(a) + f(b)
)
И тогда всё сработает, как задумано.
Выбор имени функции
Функция – это действие. Поэтому имя функции обычно является глаголом. Оно должно быть простым, точным и описывать действие функции, чтобы программист, который будет читать код, получил верное представление о том, что делает функция.
Как правило, используются глагольные префиксы, обозначающие общий характер действия, после которых следует уточнение. Обычно в командах разработчиков действуют соглашения, касающиеся значений этих префиксов.
Например, функции, начинающиеся с "show" обычно что-то показывают.
Функции, начинающиеся с…
• "get…" – возвращают значение,
• "calc…" – что-то вычисляют,
• "create…" – что-то создают,
• "check…" – что-то проверяют и возвращают логическое значение, и т.д.
Примеры таких имён:
showMessage(..) // показывает сообщение
getAge(..) // возвращает возраст (в каком-либо значении)
calcSum(..) // вычисляет сумму и возвращает результат
createForm(..) // создаёт форму (и обычно возвращает её)
checkPermission(..) // проверяет доступ, возвращая true/false
Благодаря префиксам, при первом взгляде на имя функции становится понятным что делает её код, и какое значение она может возвращать.
Одна функция – одно действие
Функция должна делать только то, что явно подразумевается её названием. И это должно быть одним действием.
Два независимых действия обычно подразумевают две функции, даже если предполагается, что они будут вызываться вместе (в этом случае мы можем создать третью функцию, которая будет их вызывать).
Несколько примеров, которые нарушают это правило:
• getAge – будет плохим выбором, если функция будет выводить alert с возрастом (должна только возвращать его).
• createForm – будет плохим выбором, если функция будет изменять документ, добавляя форму в него (должна только создавать форму и возвращать её).
• checkPermission – будет плохим выбором, если функция будет отображать сообщение с текстом доступ разрешён/запрещён (должна только выполнять проверку и возвращать её результат).
В этих примерах использовались общепринятые смыслы префиксов. Конечно, вы в команде можете договориться о других значениях, но обычно они мало отличаются от общепринятых. В любом случае вы и ваша команда должны точно понимать, что значит префикс, что функция с ним может делать, а чего не может.
Function Expression
Функция в JavaScript – это не магическая языковая структура, а особого типа значение.
Синтаксис, который мы использовали до этого, называется Function Declaration (Объявление Функции):
function sayHi() {
alert( "Привет" );
}
Существует ещё один синтаксис создания функций, который называется Function Expression (Функциональное Выражение).
Оно выглядит вот так:
let sayHi = function() {
alert( "Привет" );
};
В коде выше функция создаётся и явно присваивается переменной, как любое другое значение. По сути без разницы, как мы определили функцию, это просто значение, хранимое в переменной sayHi.
Смысл обоих примеров кода одинаков: "создать функцию и поместить её значение в переменную sayHi".
Мы можем даже вывести это значение с помощью alert:
function sayHi() {
alert( "Привет" );
}
alert( sayHi ); // выведет код функции
Обратите внимание, что последняя строка не вызывает функцию sayHi, после её имени нет круглых скобок. Существуют языки программирования, в которых любое упоминание имени функции совершает её вызов. JavaScript – не один из них.
В JavaScript функции – это значения, поэтому мы и обращаемся с ними, как со значениями. Код выше выведет строковое представление функции, которое является её исходным кодом.
Конечно, функция – не обычное значение, в том смысле, что мы можем вызвать его при помощи скобок: sayHi().
Но всё же это значение. Поэтому мы можем делать с ним то же самое, что и с любым другим значением.
Мы можем скопировать функцию в другую переменную:
function sayHi() { // (1) создаём
alert( "Привет" );
}
let func = sayHi; // (2) копируем
func(); // Привет // (3) вызываем копию (работает)!
sayHi(); // Привет // прежняя тоже работает (почему бы нет)
Давайте подробно разберём всё, что тут произошло:
1. Объявление Function Declaration (1) создало функцию и присвоило её значение переменной с именем sayHi.
2. В строке (2) мы скопировали её значение в переменную func. Обратите внимание (ещё раз): нет круглых скобок после sayHi. Если бы они были, то выражение func = sayHi() записало бы результат вызова sayHi() в переменную func, а не саму функцию sayHi.
3. Теперь функция может быть вызвана с помощью обеих переменных sayHi() и func().
Заметим, что мы могли бы использовать и Function Expression для того, чтобы создать sayHi в первой строке:
let sayHi = function() {
alert( "Привет" );
};
let func = sayHi;
// ...
Результат был бы таким же.
Function Expression в сравнении с Function Declaration
Давайте разберём ключевые отличия Function Declaration от Function Expression.
Во-первых, синтаксис: как определить, что есть что в коде.
• Function Declaration: функция объявляется отдельной конструкцией «function…» в основном потоке кода.
• // Function Declaration
• function sum(a, b) {
• return a + b;
}
• Function Expression: функция, созданная внутри другого выражения или синтаксической конструкции. В данном случае функция создаётся в правой части «выражения присваивания» =:
• // Function Expression
• let sum = function(a, b) {
• return a + b;
};
Более тонкое отличие состоит, в том, когда создаётся функция движком JavaScript.
Function Expression создаётся, когда выполнение доходит до него, и затем уже может использоваться.
После того, как поток выполнения достигнет правой части выражения присваивания let sum = function… – с этого момента, функция считается созданной и может быть использована (присвоена переменной, вызвана и т.д. ).
С Function Declaration всё иначе.
Function Declaration можно использовать во всем скрипте (или блоке кода, если функция объявлена в блоке).
Другими словами, когда движок JavaScript готовится выполнять скрипт или блок кода, прежде всего он ищет в нём Function Declaration и создаёт все такие функции. Можно считать этот процесс «стадией инициализации».
И только после того, как все объявления Function Declaration будут обработаны, продолжится выполнение.
В результате, функции, созданные, как Function Declaration могут быть вызваны раньше своих определений.
Например, так будет работать:
sayHi("Вася"); // Привет, Вася
function sayHi(name) {
alert( `Привет, ${name}` );
}
Функция sayHi была создана, когда движок JavaScript подготавливал скрипт к выполнению, и такая функция видна повсюду в этом скрипте.
…Если бы это было Function Expression, то такой код вызвал бы ошибку:
sayHi("Вася"); // ошибка!
let sayHi = function(name) { // (*) магии больше нет
alert( `Привет, ${name}` );
};
Функции, объявленные при помощи Function Expression, создаются тогда, когда выполнение доходит до них. Это случится только на строке, помеченной звёздочкой (*). Слишком поздно.
Ещё одна важная особенность Function Declaration заключается в их блочной области видимости.
Когда использовать Function Declaration, а когда Function Expression?
Как правило, если нам понадобилась функция, в первую очередь нужно рассматривать синтаксис Function Declaration, который мы использовали до этого. Он даёт нам больше свободы в том, как мы можем организовывать код. Функции, объявленные таким образом, можно вызывать до их объявления.
Также функции вида function f(…) {…} чуть более заметны в коде, чем let f = function(…) {…}. Function Declaration легче «ловятся глазами».
…Но если Function Declaration нам не подходит по какой-то причине (мы рассмотрели это в примере выше), то можно использовать объявление при помощи Function Expression.
Функции-стрелки, основы
Существует ещё более простой и краткий синтаксис для создания функций, который часто лучше, чем синтаксис Function Expression.
Он называется «функции-стрелки» или «стрелочные функции» (arrow functions), т.к. выглядит следующим образом:
let func = (arg1, arg2, ...argN) => expression
…Такой код создаёт функцию func с аргументами arg1..argN и вычисляет expression с правой стороны с их использованием, возвращая результат.
Другими словами, это более короткий вариант такой записи:
let func = function(arg1, arg2, ...argN) {
return expression;
};
Давайте взглянем на конкретный пример:
let sum = (a, b) => a + b;
/* Более короткая форма для:
let sum = function(a, b) {
return a + b;
};
*/
alert( sum(1, 2) ); // 3
То есть, (a, b) => a + b задаёт функцию с двумя аргументами a и b, которая при запуске вычисляет выражение справа a + b и возвращает его результат.
• Если у нас только один аргумент, то круглые скобки вокруг параметров можно опустить, сделав запись ещё короче:
• // тоже что и
• // let double = function(n) { return n * 2 }
• let double = n => n * 2;
•
alert( double(3) ); // 6
• Если нет аргументов, указываются пустые круглые скобки:
• let sayHi = () => alert("Hello!");
•
sayHi();
Функции-стрелки могут быть использованы так же, как и Function Expression.
Например, для динамического создания функции:
let age = prompt("Сколько Вам лет?", 18);
let welcome = (age < 18) ?
() => alert('Привет') :
() => alert("Здравствуйте!");
welcome(); // теперь всё в порядке
Поначалу функции-стрелки могут показаться необычными и трудночитаемыми, но это быстро пройдёт, как только глаза привыкнут к этим конструкциям.
Они очень удобны для простых однострочных действий, когда лень писать много букв.
Многострочные стрелочные функции
В примерах выше аргументы использовались слева от =>, а справа вычислялось выражение с их значениями.
Порой нам нужно что-то посложнее, например, выполнить несколько инструкций. Это также возможно, нужно лишь заключить инструкции в фигурные скобки. И использовать return внутри них, как в обычной функции.
Например:
let sum = (a, b) => { // фигурная скобка, открывающая тело многострочной функции
let result = a + b;
return result; // при фигурных скобках для возврата значения нужно явно вызвать return
};
alert( sum(1, 2) ); // 3
Наиболее часто используемые методы для строк и чисел.
Их можно протестировать в нашем скрипте, для детального понимания их работы
const str = "teSt";
console.log(str);
console.log(str.length); // получает длинну строки или массива
console.log(str[1]); //так можно получить конкретный элемент по индексу
console.log(str.toUpperCase());//метод изменения регистра вверх
console.log(str.toLowerCase());//метод изменения регистра вниз
console.log(str.toLowerCase());//метод изменения регистра вниз
const fruit = "some fruit";
console.log(fruit.indexOf("fruit"));
//метод определяет с какого индекса начинается выбранный элемент строки или есть ли он в строке
const logg = 'hello worldd';
console.log(logg.slice(6, 11));//выводит только из диапазона по индексу(начало конец)
console.log(logg.slice(6)); // так указывается от и до конца
console.log(logg.substring(6, 11)); //делает что и выше только без отрицательных цифр
console.log(logg.substr(6, 5)); //выбирает с какого индекса сколько символов
const num = 12.2;
console.log(Math.round(num)); // округляет число
const test = "12.2px";
console.log(parseInt(test)); // переводит строку в др систему счисления и округляется
console.log(parseFloat(test)); //возвращает с плавающей точкой