Функции в JavaScript и классический способ их создания

Функции в JavaScript и классический способ их создания
Содержание:
  1. Что такое функция?
  2. Объявление и вызов функции
  3. Параметры и аргументы
  4. Передача значения по ссылке
  5. Работа с аргументами через arguments
  6. Колбэк функции
  7. Функция – это объект
  8. Возврат значения
  9. Значение параметров функции по умолчанию
  10. Остаточные параметры
  11. Что такое встроенные (стандартные) функции
  12. Комментарии

Статья, в которой рассмотрим, что такое функция и зачем она нужна. Разберём классический способ её объявления, параметры, аргументы и оператор return.

Что такое функция?

Функция – это фрагмент кода, который можно выполнить многократно в разных частях программы. Т.е. одни и те же действия много раз с разными исходными значениями.

В следующем примере имеются повторяющиеся блоки кода, которые можно вынести отдельно в JavaScript функцию:

Повторяющие блоки кода, которые можно вынести в JavaScript функцию

Функция sum, в которую вынесен повторяющийся блок кода. После этого в местах программы, в которых его нужно выполнять, просто помещён вызов этой функции:

let a = 5;
let b = 7;

function sum(a, b) {
  sum = a + b;
  console.log(sum);
}

sum(a, b); // 12

a = 10;
b = 4;

sum(a, b); // 14

Это один из классических сценариев использования функций, который позволяет значительно упростить написание программ на JavaScript.

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

JavaScript позволяет создавать функцию различными способами:

  • Function Declaration;
  • Function Expression;
  • Arrow Function.

В этой статье разберём первый классический способ, который называется Function Declaration.

Объявление и вызов функции

Операции с функцией в JavaScript можно разделить на 2 этапа:

  • объявление (создание) функции;
  • вызов (выполнение) этой функции.

1. Объявление функции. Написание функции посредством Function Declaration начинается с ключевого слова function. После чего указывается имя, круглые скобки, внутрь которых при необходимости помещаются параметры, и тело, заключённое в фигурные скобки. Имя функции ещё очень часто называют названием. В теле пишутся те действия, которые вы хотите выполнить с помощью этой функции.

// nameFn – имя функции, params – параметры
function nameFn (params) {
  // тело функции
}

Например:

// объявляем функцию someName
function someName() {
  console.log('Вы вызвали функцию someName!');
}
// function – ключевое слово, которое означает, что мы создаём функцию
// someName – имя функции
// () – круглые скобки, внутри которых при необходимости описываются параметры
// { ... } – тело функции

При составлении имени функции необходимо руководствоваться такими же правилами, что для переменных. Т.е. можно использовать буквы, цифры (0 – 9), знаки «$» и «_». В качестве букв рекомендуется использовать английский алфавит (a-z, A-Z). Имя функции, также как и имя переменной не может начинаться с цифры.

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

Параметры предназначены для получения значений, переданных в функцию, по имени. Их именование осуществляется также как переменных:

// объявляем функцию с двумя параметрами
  function fullname(firstname, lastname) {
  console.log(`${firstname} ${lastname}`);
}

Параметры ведут себя как переменные и в теле функции мы имеем доступ к ним. Значения этих переменных (в данном случае firstname и lastname) определяются в момент вызова функции. Обратиться к ним вне функции нельзя.

Если параметры не нужны, то круглые скобки всё равно указываются.

2. Вызов функции. Объявленная функция сама по себе не выполняется. Запуск функции выполняется посредством её вызова.

При этом когда мы объявляем функцию с именем, мы тем самым по сути создаём новую переменную с этим названием. Эта переменная будет функцией. Для вызова функции необходимо указать её имя и две круглые скобки, в которых при необходимости ей можно передать аргументы. Отделение одного аргумента от другого выполняется с помощью запятой.

// объявляем функцию someName
function someName() {
  console.log('Вы вызвали функцию someName!');
}
// вызываем функцию someName
someName();

Параметры и аргументы

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

Аргументы – это значения, которые мы передаём в функцию в момент её вызова.

// userFirstName и userLastName – параметры (userFirstName будет иметь значение первого аргумента, а userLastName соответственно второго в момент вызова этой функции)
function sayWelcome (userFirstName, userLastName) {
  console.log(`Добро пожаловать, ${userLastName} ${userFirstName}`);
}
// 'Иван' и 'Иванов' – аргументы
sayWelcome('Иван', 'Иванов'); // Добро пожаловать, Иванов Иван
// 'Петр' и 'Петров' – аргументы
sayWelcome('Петр', 'Петров'); // Добро пожаловать, Петров Петр

При вызове функции в JavaScript количество аргументов не обязательно должно совпадать с количеством параметров. Если аргумент не передан, а мы хотим его получить с помощью параметра, то он будет иметь значение undefined.

function sayWelcome (userFirstName, userLastName) {
  console.log( `Добро пожаловать, ${userLastName} ${userFirstName} `);
}
// с одним аргументом
sayWelcome('Иван'); // Добро пожаловать, undefined Иван
// без передачи аргументов
sayWelcome(); // Добро пожаловать, undefined undefined

Передача аргументов примитивных типов осуществляется по значению. Т.е. значение переменной не изменится снаружи, если мы изменим её значение внутри функции.

let a = 7;
let b = 5;

function sum (a, b) {
  a *= 2; // 14
  console.log(a + b);
}
sum(a, b); // 19
console.log(a); // 7

Передача значения по ссылке

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

// объявим переменную someUser и присвоим ей объект, состоящий из двух свойств
const someUser = {
  firstname: 'Петр',
  lastname: 'Петров'
}
// объявим функцию changeUserName
function changeUserName(user) {
  // изменим значение свойства firstname на новое
  user.firstname = 'Александр';
}
// вызовем функцию changeUserName
changeUserName(someUser);
// выводим значение свойства firstname в консоль
console.log(someUser.firstname); // Александр

В этом примере переменные someUser и user ссылаются на один и тот же объект в памяти. И когда мы изменяем объект внутри функции, то someUser тоже изменится.

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

Чтобы избежать изменение внешнего объекта, который мы передаем в функцию через аргумент, необходимо создать копию этого объекта, например, посредством Object.assign:

const someUser = {
  firstname: 'Петр',
  lastname: 'Петров'
}
function changeUserName(user) {
  // создадим копию объекта user
  const copyUser = Object.assign({}, user);
  // изменим значение свойства firstname на новое
  copyUser.firstname = 'Александр';
  // вернём копию объекта в качестве результата
  return copyUser;
}

// вызовем функцию и сохраним результат вызова функции в переменную updatedUser
const updatedUser = changeUserName(someUser);
// выводим значение свойства firstname в консоль для объекта someUser
console.log(someUser.firstname); // Петр
// выводим значение свойства firstname в консоль для объекта updatedUser
console.log(updatedUser.firstname); // Александр

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

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

Локальные и внешние переменные

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

let a = 7;
// объявление функции sum
function sum(a) {
  // локальная переменная функции
  let b = 8;
  console.log(a + b);
}
// вызов функции sum
sum(a);
console.log(b); // Error: b is not defined

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

// внешние переменные
let a = 7;
let b = 3;
function sum() {
  // локальная переменная
  let a = 8;
  // изменение значения внешней переменной (т.к. b нет внутри функции)
  b = 4;
  console.log(a + b);
}
sum(); // 12

Работа с аргументами через arguments

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

function myFn() {
  // проверим является ли arguments обычным массивом
  console.log(Array.isArray(arguments)); // false
  // количество аргументов
  console.log(arguments.length); // 0
}

myFn(); // false

Доступ к аргументам через arguments выполняется точно также как к элементам обычного массива, т.е. по порядковому номеру:

// объявление функции sum
function sum() {
  const num1 = arguments[0]; // получаем значение 1 аргумента
  const num2 = arguments[1]; // получаем значение 2 аргумента
  console.log(num1 + num2);
}

sum(7, 4); // 11

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

function sum() {
  let sum = 0;
  // arguments.length - число аргументов
  for (let i = 0, length = arguments.length; i < length; i++) {
    if (typeof arguments[i] === 'number') {
      sum += arguments[i];
    }
  }
  console.log(sum);
}

sum(4, 20, 17, -6); // 35
sum('', 3, -5, 32, null); // 30

Через цикл for...of этот пример можно записать так:

function sum() {
  let sum = 0;
  for (argument of arguments) {
    if (typeof argument === 'number') {
      sum += argument;
    }
  }
  console.log(sum);
}

При необходимости arguments можно преобразовать в обычный массив:

function names() {
  // превращаем arguments в полноценный массив
  const args = Array.from(arguments);
  console.log(args);
}
names('Даша', 'Маша', 'Нина'); // ["Даша", "Маша", "Нина"]

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

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

function fnA(a, b) {
  const c = 4;
  function fnB(d) {
    console.log(a + b + c + d);
  }
  fnB(1);
}
fnA(3, 5); // 13
fnA(4, 7); // 16
// переменная a не доступна за пределами функции fnA
console.log(a); // Uncaught ReferenceError: a is not defined

При этом внутри функции мы имеем доступ к внешним переменных, но только к тем, которых с таким же именем нет в текущей функции:

const a = 10;
function fa(b) {
  console.log(a + b);
}

fa(7); // 17

Колбэк функции

Колбэк функция (от английского callback function) – это обычная функция, которая просто вызывается внутри другой функции. Такие функции ещё называются функциями обратного вызова. Они очень часто применяются в асинхронном коде.

Передаётся колбэк функция в другую через аргумент:

// колбэк функция
function cb() {
  console.log('callback');
}
// функция, которая будет принимать на вход колбэк функцию
function fnWithCb(cbFn) {
  console.log('before calling the callback function');
  cbFn();
}
// вызываем функцию fnWithCb() и передаём ей в качестве аргумента колбэк функцию cb
fnWithCb(cb);

В этом примере имеются две функции:

  • cb – её будем использовать в роли колбэк функции, т.е. вызывать в fnWithCb;
  • fnWithCb – эта функция, которая содержит параметр cbFn, он будет при её вызове принимать другую функцию (в данном случае cb).

Таким образом, функция cb вызывается внутри функции fnWithCb. В неё она передаётся как аргумент. Без вызова fnWithCb она не вызовется, т.к. она вызывается только внутри fnWithCb.

Другой пример:

JavaScript
// объявим колбэк функцию
function printToLog(message) {
  console.log(message);
}
// объявим функцию, имеющую 3 параметра
function sum(num1, num2, callback) {
  // вычислим сумму 2 значений и запишем его в result
  const result = num1 + num2;
  // вызовем колбэк функцию
  callback(result);
}
// вызовем функцию sum
sum(5, 11, printToLog);

Ещё один пример:

// колбэк функция
function setColorBody() {
  document.body.style.backgroundColor = '#00ff00';
}
// функция, которая будет вызывать функцию setColorBody через 3 секунды
setTimeout(setColorBody, 3000);

В этом примере у нас имеется функция setColorBody. В теле она содержит код, который устанавливает цвет фона <body>.

Далее вызывается функция setTimeout(). Она в свою очередь вызывает где-то внутри себя функцию, переданную ей в качестве первого аргумента. Причем вызывает не сразу, а через указанное количество миллисекунд. В данном случае через 3000.

Функцию setTimeout мы нигде не объявляли, т.к. она присутствует в JavaScript по умолчанию. Оня является методом глобальное объекта window в браузере и global в Node.js.

Обратите внимание, что в setTimeout мы просто передаём функцию setColorBody. Т.е. сами её не вызываем.

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

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

Функция – это объект

Функция в JavaScript, как уже было отмечено выше – это определённый тип объектов, которые можно вызывать. А если функция является объектом, то у неё как у любого объекта имеются свойства. Убедиться в этом очень просто. Для этого можно воспользоваться методом console.dir() и передать ему в качестве аргумента функцию.

Убеждаемся что функция является объектом и у неё есть свойства

На изображении показана структура функции sum. Используя точечную запись, мы например, можем получить название функции (свойство name) и количество параметров(length):

console.log(sum.name); // sum
console.log(sum.length); // 2

Узнать является ли переменная функцией можно с помощью typeof:

function myFunc() {};

console.log(typeof myFunc); // function

Например, проверим является переменная колбэк функцией перед тем её вызвать:

function sum(num1, num2, callback) {
  const result = num1 + num2;
  if (typeof callback === 'function') {
    callback(result);
  }
}

Возврат значения

Функция всегда возвращает значение, даже если мы не указываем это явно. По умолчанию она возвращает значение undefined.

Для явного указания значения, которое должна возвращать функция используется инструкция return. При этом значение или выражение, результат которого должна вернуть функция задаётся после этого ключевого слова.

// expression – выражение, результат которого будет возвращен функцией myFn
function myFn() {
  return expression;
}

Если return не указать, то функция всё равно возвратит значение, в данном случае undefined.

function sum(a, b) {
  console.log(a + b);
}

// вызовем функцию и сохраним её результат в константу result
const result = sum(4, 3);
// выведем значение переменной result в консоль
console.log(result); // undefined

С использованием инструкции return:

function sum(a, b) {
  // вернём в качестве результата a + b
  return a + b;
}

// вызовем функцию и сохраним её результат в константу result
const result = sum(4, 3);
// выведем значение переменной result в консоль
console.log(result); // 7

Инструкции, расположенные после return никогда не выполняются:

function sum(a, b) {
  // вернём в качестве результата a + b
  return a + b;
  // код, расположенный после return никогда не выполнится
  console.log('Это сообщение не будет выведено в консоль');
}

sum(4, 90);

В этом примере, функция sum возвращает число 94 и прекращает выполнение дальнейших инструкций после return. А так как работа функции закончилась, то сообщение в консоль выведено не будет.

Функция, которая возвращает функцию

В качестве результата функции мы можем также возвращать функцию.

Например:

function outer(a) {
  return function(b) {
    return a * b;
  }
}

// в one будет находиться функция, которую возвращает outer(3)
const one = outer(3);
// в two будет находиться функция, которую возвращает outer(4)
const two = outer(4);

// выведем в консоль результат вызова функции one(5)
console.log(one(5)); // 15
// выведем в консоль результат вызова функции two(5)
console.log(two(5)); // 20

Вызовы функции outer(3) и outer(4) возвращают одну и туже функцию, но первая запомнила, что a = 3, а вторая - что a = 4. Это происходит из-за того, что функции в JavaScript «запоминают» окружение, в котором они были созданы. Этот приём довольно часто применяется на практике. Так как с помощью него мы можем, например, на основе одной функции создать другие, которые нужны.

В примере, приведённом выше, мы могли также не создавать дополнительные константы one и two. А вызвать сразу после вызова первой функции вторую.

// выведем в консоль результат вызова функции one(5)
console.log(outer(3)(5)); // 15
// выведем в консоль результат вызова функции two(5)
console.log(outer(4)(5)); // 20

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

Функцию, приведённую в коде мы можем также создать и так:

function outer(a) {
  function inner(b) {
    return a * b;
  }
  return inner;
}

Кроме этого в качестве результата мы можем также возвратить внешнюю функцию:

function fa() {
  return 'Привет!';
}

function fb() {
  return fa;
}

fb()(); // Привет!

Рекурсия

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

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

Например, использование рекурсии для вычисления факториала числа:

function fact(n) {
  // условие выхода из рекурсии
  if (n === 1) {
    return 1;
  }

  // возвращаем вызов функции fact(n - 1) умноженное на n
  return fact(n - 1) * n;
}
console.log(fact(5)); // 120

Пример, в котором используя рекурсию выведем числа от указанного до 10:

function counter(value) {
  // условие выхода из рекурсии
  if (value < 10) {
    console.log(value);

    // возвращаем вызов функции counter(value + 1)
    return counter(value + 1);
  }
}

counter(1); // 1, 2, 3, 4, 5, 6, 7, 8, 9
counter(7); // 7, 8, 9

Перегрузка функций в JavaScript

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

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

Например, того чтобы проверить имеет параметр значение или нет, мы можем проверить его значения на undefined. Узнать количества переданных аргументов функции можно через arguments.length. Определить значения параметра можно используя typeof или instanceof.

Например, создадим функцию bodyBgColor, которая будет иметь 2 режима работы. Если её вызвать без аргументов, то она будет возвращать цвет фона body. А если с текстовым аргументом, то она будет устанавливать цвет фона body.

// объявление функции bodyBgColor
function bodyBgColor(color) {
  // если параметр color имеет в качестве значения строку, то установим цвет фона body
  if (typeof color === 'string') {
    document.body.style.backgroundColor = color;
  }

  // вернём в качестве результата текущий цвет фона body
  return getComputedStyle(document.body).backgroundColor;
}

// получим текущий цвет body и выведем его в консоль
console.log(bodyBgColor());

// установим новый цвет фона body
bodyBgColor('green');

Пример реализации «перегруженной» функции для вычисления оптимального количества ккал, которых необходимо человеку в день:

function calculateСalories(gender, height) {
  let result = gender === 'man' ? (height - 100) * 20 : (height - 105) * 19;
  if (typeof arguments[2] === 'number') {
    result *= arguments[2];
  }
  return result.toFixed(0);
}

console.log(`Оптимальное кол-во ккал: ${calculateСalories('man', 185)}`);
console.log(`Оптимальное кол-во ккал: ${calculateСalories('woman', 168, 1.2)}`);
console.log(`Оптимальное кол-во ккал: ${calculateСalories('woman', 168)}`);

Значение параметров функции по умолчанию

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

function setBgColor(selector, color = 'green') {
  const el = document.querySelector(selector);
  el.style.backgroundColor = color;
}
setBgColor('body');

При вызове функции с одним аргументом, второму параметру будет автоматически присвоено строка 'green'.

Работу параметра по умолчанию можно представить так:

function setBgColor(selector, color) {
  const el = document.querySelector(selector);
  color = color === undefined ? 'green' : color;
  el.style.backgroundColor = color;
}
setBgColor('body');

Пример функции addNewMessage, в которой один из параметров имеет дефолтное значение. Причем это значение будет меняться в зависимости от текущей даты:

const messages = [];
function addNewMessage(text, date = new Date()) {
  messages.push({
    text,
    date
  })
};
addNewMessage('Как сделать вкусный коктейль в блендере?');
addNewMessage('Какое мороженое лучше для коктейля?');
console.log(messages);

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

Остаточные параметры

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

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

// ...nums – остаточные параметры
function calc(action, ...nums) {
  const initialValue = action === '*' ? 1 : 0;
  return nums.reduce((result, current) => {
    return action === '+' ? result + current : action === '*' ? result * current : 0;
  }, initialValue)
}
console.log(calc('+', 3, 4, 21, -4)); // 24
console.log(calc('*', 1, 4, 3)); // 12

В описании параметров ...nums должен всегда быть последним. Если что-то указать после него, то это вызовет ошибку:


function calc(action, ...nums, cb) {
  // ...
}

calc(); // Uncaught SyntaxError: Rest parameter must be last formal parameter

Что такое встроенные (стандартные) функции

В JavaScript имеется огромный набор встроенных (стандартных) функций. Данные функции уже описаны в самом движке браузера. Практически все они являются методами того или иного объекта.

Например, для того чтобы вызвать встроенную функцию (метод) alert, её не надо предварительно объявлять. Она уже описана в браузере. Вызов метода alert осуществляется посредством указания имени, круглых скобок и аргумента внутри них. Данный метод предназначен для вывода сообщения на экран в форме диалогового окна. Текстовое сообщение берётся из значения параметра данной функции.

// вызов функции alert
alert("Некоторый текст");
JavaScript - Вызов функции alert

Функция в JavaScript в результате своего выполнения всегда возвращает результат, даже если он явно не определён с помощью оператора return. Этот результат значение undefined.

// 1. функция, не возвращающая никакого результата
function sayWelcome (userFirstName, userLastName) {
  console.log("Добро пожаловать, " + userLastName + " " + userFirstName);
}
// попробуем получить результат у функции, которая ничего не возвращает
console.log(sayWelcome ("Иван", "Иванов"));
// 2. функция, содержащая оператор return без значения
function sayDay (day) {
  day = "Сегодня, " + day;
  return;
  //эта инструкция не выполнится, т.к. она идёт после оператора return
  console.log(day);
}
// попробуем получить результат у функции, которая содержит оператор return без значения
console.log(sayDay("21 февраля 2016г."));
JavaScript - Получить значение у функции, которая ничего не возвращает

Такой же результат будет получен, если для оператора return не указать возвращаемое значение.

Следующая тема: Функциональные выражения и стрелочные функции в JavaScript.

Комментарии: 67

Lubov
Lubov

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

const str = 'Московский государственный университет ';
const buildAcronym = (str = '') => {
  const strArr = str.split(' ');
  let res = '';
  strArr.forEach(el => {
    const [char] = el;
    if (char === char.toUpperCase() && char !== char.toLowerCase()) {
      res += char;
    }
  });
  return res;
}
console.log(buildAcronym(str));

выдает ошибку

Александр Мальцев
Александр Мальцев

Добрый день! Можно, например, так:

const str = 'Московский государственный университет ';
const buildAcronym = (str = '') => {
  const strArr = str.trim().split(' ');
  return strArr.map(el => {
    return el.trim() !== '' ? el.trim()[0].toUpperCase() : '';
  }).join('');
};
console.log(buildAcronym(str));
DeKn
DeKn

Добрый день! В примере про колбэк функцию наверное есть опечатка. Я запутался с вызовом когда разбирал этот пример. Спасибо! Описание картинки

Александр Мальцев
Александр Мальцев

Здравствуйте! Спасибо за найденную опечатку.

oleg_dz
oleg_dz
Добрый день!
Создал функцию-калькулятор с prompt. Как сделать, чтобы после каждого выполнения условия if гость снова попадал в prompt?
Спасибо.
function getCalculate() {
  let ask = prompt('Выбери тип операции', '1 умножить | 2 сложить | 3 степень | 4 делить | 5 вычесть')
  if (ask == '1') {
    res1 = +prompt('a ?')
    res2 = +prompt('b ?')
    return result = res1 * res2;
  } else if (ask == '2') {
    res1 = +prompt('a ?')
    res2 = +prompt('b ?')
    return result = res1 + res2;
  } else if (ask == '3') {
    res1 = +prompt('a ?')
    res2 = +prompt('b ?')
    return result = res1 ** res2;
  } else if (ask == '4') {
    res1 = +prompt('a ?')
    res2 = +prompt('b ?')
    return result = (res1 / res2).toFixed(2);
  } else if (ask == '5') {
    res1 = +prompt('a ?')
    res2 = +prompt('b ?')
    return result = res1 - res2;
  } else {
    return 'Повторите попытку';
  }
}
alert(getCalculate())
Александр Мальцев
Александр Мальцев
Добрый день! Можно использовать рекурсию, то есть внутри функции вызывать её саму же:
function runCalculate() {
  function getCalculate() {
    let ask = prompt('Выбери тип операции', '1 умножить | 2 сложить | 3 степень | 4 делить | 5 вычесть')
    if (ask == '1') {
      res1 = +prompt('a ?')
      res2 = +prompt('b ?')
      return result = res1 * res2;
    } else if (ask == '2') {
      res1 = +prompt('a ?')
      res2 = +prompt('b ?')
      return result = res1 + res2;
    } else if (ask == '3') {
      res1 = +prompt('a ?')
      res2 = +prompt('b ?')
      return result = res1 ** res2;
    } else if (ask == '4') {
      res1 = +prompt('a ?')
      res2 = +prompt('b ?')
      return result = (res1 / res2).toFixed(2);
    } else if (ask == '5') {
      res1 = +prompt('a ?')
      res2 = +prompt('b ?')
      return result = res1 - res2;
    } else {
      return 'Повторите попытку';
    }
  }
  alert(getCalculate())
  runCalculate()
}
runCalculate()
oleg_dz
oleg_dz
Спасибо огромное. Надо всё же эта тему изучить.
oleg_dz
oleg_dz
А есть ли на вашем ресурсе инфа про рекурсию?
Александр Мальцев
Александр Мальцев
В этой статье имеется раздел про рекурсию. В нём даётся описание, что такое рекурсия и 2 примера. Изучите эти примеры внимательно, желательно по шагам и всё поймёте.
Можно привести ещё такой простой пример для понимания рекурсии:
let i = 1;
function myFn() {
  console.log('Вызвана функция myFn: ', i);
  i++;
  // вызываем в myFn саму же эту функцию, то есть myFn, пока i < 10
  if (i < 10) {
    myFn();
  }
}

myFn();
oleg_dz
oleg_dz
Честно, не понимаю, откуда взялось после 7, 8 и 9.
Это цикл что ли?
Результат функции без рекурсии просто 7 при аргументе 7. value +1 это разве не 8?
function counter(value) {
  // условие выхода из рекурсии
  if (value < 10) {
    console.log(value);

    // возвращаем вызов функции counter(value + 1)
    return counter(value + 1);
  }
}

counter(7); //  7, 8, 9
oleg_dz
oleg_dz
Или функция будет выполняться бесконечно на каждом шаге, до цифры выхода из рекурсии?
oleg_dz
oleg_dz
Думал, как сделать выход из рекурсии на последнем условии, и ничего лучше не придумал, как применить рекурсию к каждому if, кроме последнего. Может есть другой способ.
function runCalculate() {
  let ask = prompt('Выбери тип операции', '1 умножить | 2 сложить | 3 степень | 4 делить | 5 вычесть')
  if (ask == '1') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert(arg1 * arg2);
    return runCalculate();
  } else if (ask == '2') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert(arg1 + arg2);
    return runCalculate();
  } else if (ask == '3') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert(arg1 ** arg2);
    return runCalculate();
  } else if (ask == '4') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert((arg1 / arg2).toFixed(2));
    return runCalculate();
  } else if (ask == '5') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert(arg1 - arg2);
    return runCalculate()
  } else {
    return 'Вы не ввели данные';
  }
}
alert(runCalculate())
Александр Мальцев
Александр Мальцев
Когда вы вызываете counter(7) начинает выполняться код функции. В нём сначала проверяется условие. В данном случае оно истинно (7 < 10). Следовательно, значение 7 выводится в консоль. На ключевое слово return в этом примере можно внимание не обращать, так как в нём нет никакого смысла. Теперь вызываем функцию counter(8). Это и называется рекурсией, когда внутри некоторой функции вызываем её саму же.
Сейчас всё повторяется. Проверяется условие (8 < 10). Оно снова истинно. Теперь выводится в консоль значение value, которое равно 8. После этого опять вызывается counter(9), но теперь значение аргумента уже 9.
Сейчас всё повторяется… Вызываем counter(10).
Но вот здесь условие ложно (10 < 10) и функция завершается.
В результате в консоли увидим числа: 7, 8, 9.
Александр Мальцев
Александр Мальцев
Вызовите вызов функции просто в конце:
function runCalculate() {
  let ask = prompt('Выбери тип операции', '1 умножить | 2 сложить | 3 степень | 4 делить | 5 вычесть')
  if (ask == '1') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert(arg1 * arg2);
  } else if (ask == '2') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert(arg1 + arg2);
  } else if (ask == '3') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert(arg1 ** arg2);
  } else if (ask == '4') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert((arg1 / arg2).toFixed(2));
  } else if (ask == '5') {
    arg1 = +prompt('a ?')
    arg2 = +prompt('b ?')
    alert(arg1 - arg2);
  } else {
    return 'Вы не ввели данные';
  }
  runCalculate()
}
alert(runCalculate())
oleg_dz
oleg_dz
Здорово, а почему в данном случае на последнем условии выход произошел?
Я поэкспериментировал. Обернул в дополнительные фигурные скобки блок с условиями.
В данном случае идет возврат в модальное окно после else. В чем разница?
function runCalculate() {
  let ask = prompt('Выбери тип операции', '1 умножить | 2 сложить | 3 степень | 4 делить | 5 вычесть')
  {
    if (ask == '1') {
      arg1 = +prompt('a ?')
      arg2 = +prompt('b ?')
      alert(arg1 * arg2);
    } else if (ask == '2') {
      arg1 = +prompt('a ?')
      arg2 = +prompt('b ?')
      alert(arg1 + arg2);
    } else if (ask == '3') {
      arg1 = +prompt('a ?')
      arg2 = +prompt('b ?')
      alert(arg1 ** arg2);
    } else if (ask == '4') {
      arg1 = +prompt('a ?')
      arg2 = +prompt('b ?')
      alert((arg1 / arg2).toFixed(2));
    } else if (ask == '5') {
      arg1 = +prompt('a ?')
      arg2 = +prompt('b ?')
      alert(arg1 - arg2);
    } else {
      alert('Вы не ввели данные');
    }
  }
  return runCalculate()
}
alert(runCalculate())
Александр Мальцев
Александр Мальцев
А зачем в фигурные скобки if..else вы обернули, в этом нет смысла.
Если нужен выход из рекурсии, то добавьте после инструкции alert('Вы не ввели данные') просто ключевое слово return:
...else {
  alert('Вы не ввели данные');
  return;
}
oleg_dz
oleg_dz
Все понял, точно же. Return прерывает, спасибо
pipa
pipa
Здравствуйте
Подскажите пожалуйста, почему при клонировании объекта внутри функции, копируется аргумент самой функции (user), а не объекта (someUser) snipboard.io/7EHC2Q.jpg?
Александр Мальцев
Александр Мальцев
Здравствуйте!
Просто такой пример. В большинстве случаев функция оперирует с аргументами, которые мы в неё передаём. Если бы мы так написали, то бы жёстко были привязаны к этому объекту и в самой функции отпал бы смысл. А так мы можем функции передать любой объект:
const user2 = changeUserName({ firstname: 'Василий', lastName: 'Носков' });
D_M
D_M
Александр, добрый день!
Только начал изучать JS. Есть задача. Функцию getChange, написанную на занятии с помощью рекурсии реализовать (переписать) с помощью цикла.
Код функции:
function getChange(num) {
  if (num >= 10) {
    console.log(10);
    getChange(num - 10);
  } else if (num >= 5) {
    console.log(5);
    getChange(num - 5);
  } else if (num >= 2) {
    console.log(2);
    getChange(num - 2);
  } else if (num >= 1) {
    console.log(1);
    getChange(num - 1);
  } else {
    console.log('Вся сдача выдана');
  }
}
Добавил цикл, но не работает. Если, например брать число 37, то зацикливается после 2. Подскажите, пожалуйста, что неправильно сделал?
function getChange(num) {
  while (num > 0) {
    if (num >= 10) {
      console.log(10);
      getChange(num - 10);
    } else if (num >= 5) {
      console.log(5);
      getChange(num - 5);
    } else if (num >= 2) {
      console.log(2);
      getChange(num - 2);
    } else if (num >= 1) {
      console.log(1);
      getChange(num - 1);
    }
  }
}
Александр Мальцев
Александр Мальцев
Через цикл будет так:
function getChange(num) {
  while (num > 0) {
    if (num >= 10) {
      console.log(10);
      num -= 10;
    } else if (num >= 5) {
      console.log(5);
      num -= 5;
    } else if (num >= 2) {
      console.log(2);
      num -= 2;
    } else if (num >= 1) {
      console.log(1);
      num -= 1;
    }
  }
  console.log('Вся сдача выдана');
}
Здесь уже не нужно вызвать функцию внутри функции, то есть использовать рекурсию.
D_M
D_M
Спасибо большое!
А почему циклились на 2 (в моем варианте)? Я смотрел в devtools пошагово, там после цикла с 0, возвращалась 2-ка и..., по новой…
Александр Мальцев
Александр Мальцев
Потому что цикл у вас никак не завершается. Он выполняется бесконечно. Чтобы цикл завершился в данном случае необходимо, чтобы условие (num > 0) стало ложным. Но этого произойти не может, так как вы не уменьшаете значение num, а снова вызываете getChange().
D_M
D_M
Понял, благодарю!
kodziro
kodziro
Добрый вечер, помогите пожалуйста решить задачу. Только учусь, не получается, а понять, как делать хочется.
Задание. Создайте программу, проверяющую число на четность/нечетность по следующему алгоритму:
1. Создать функцию, которая спрашивает у пользователя число prompt().
2. Добавить проверку: четное число или нет (четные числа делятся на 2 без остатка).
3. Добавить проверку: если число четное, функция должна вернуть «Число четное».
4. Добавить проверку: Если число нечетное, функция должна вернуть «Число нечетное».
Подсказка: вы можете использовать знак %, чтобы определить остаток от деления.
Александр Мальцев
Александр Мальцев
Добрый день!
Пример функции:
function isEvenNumber() {
  const num = parseFloat(prompt('Введите число?'), 10);
  if (Number.isInteger(num)) {
    const result = num % 2 === 0 ? 'Число четное' : 'Число нечетное';
    return result;
  }
}
Вызываем функцию и выводим её результат в консоль:
console.log(isEvenNumber());
ana.anjee
ana.anjee
Здравствуйте, Александр! Большое спасибо за ваш блог, он для меня открытие, многие недосказанности по JS вы разложили по полочкам. Если вас не затруднит, я еще учусь, подсказать в примере перегруженной функции зачем result помножается на аргумент arguments[2]?

function calculateСalories(gender, height) {
  let result = gender === 'man' ? (height - 100) * 20 : (height - 105) * 19;
  if (typeof arguments[2] === 'number') {
    result *= arguments[2];
  }
  return result.toFixed(0);
}

console.log(`Оптимальное кол-во ккал: ${calculateСalories('man', 185)}`);
console.log(`Оптимальное кол-во ккал: ${calculateСalories('woman', 168, 1.2)}`);
console.log(`Оптимальное кол-во ккал: ${calculateСalories('woman', 168)}`);
Александр Мальцев
Александр Мальцев
Добрый день! Пожалуйста!
Это просто пример. Третий аргумент в вызове функции отвечает за активность. Если, у человека нет физической нагрузки, то третий аргумент передавать не нужно.
Если он занимается спортом 3 раза в неделю, то суточная норма калорий должна быть больше. В этом примере во сколько нужно увеличить норму потребления калорий задаётся посредством 3 аргумента.
Даниил
Даниил
Ваш сайт находка! Весь свой процесс обучения (как минимум, большую часть) я сконцентрирую тут. Спасибо авторам. Обязательно задоначу)
Александр Мальцев
Александр Мальцев
Спасибо за отзыв!
Денис
Денис
Спасибо за статьи, одно удовольствие читать!
Ігор Ярмош
Ігор Ярмош
помогите пожалуйста. Нужно написать функцию которая принимает строку и проверяєт являетса ли строка алфавитом

isAlphabet('abc') === true
isAlphabet('abd') === false
Александр Мальцев
Александр Мальцев
Пример функции isAlphabet:
function isAlphabet(str) {
  if (str.length) {
    let charCode = str[0].charCodeAt();
    for (let i = 1; i < str.length; i++) {
      charCodeNext = str[i].charCodeAt();
      if (charCodeNext - charCode !== 1) {
        return false;
      }
      charCode = charCodeNext;
    }
    return true;
  }
  return false;
}
Rimo
Rimo
Здравствуйте, Александр!
Помогите пожалуйста решить следующую задачу:

Задание: Создайте функцию getData, которая возвращает текущие дату и время.
Александр Мальцев
Александр Мальцев
Привет! Наверно, так:
function getDate() {
  return new Date();
}
Rimo
Rimo
Спасибо. А в консоль вывести результат так? console.log(getDate('Date'));
Александр Мальцев
Александр Мальцев
Почти так (аргумент передавать не нужно):
console.log( getDate() );
Gosha
Gosha
создать фуункцию greeter, которая:

принимает параметр name;
возвращает строчку-приветствие такого формата: Hi, ${name}!..
Подказка Hi, ${name}! у обратных лапках.
Александр Мальцев
Александр Мальцев
Пример функции greeter:
function greeter(name) {
  return `Hi, ${name}!`;
}
Вызов функции:
console.log( greeter('Ваня') );
Anastasiia Veselieva
Anastasiia Veselieva
Пожалуйста помогите решить задачу.
Create a my_string_formatting function which takes 3 parameters (firstname, lastname and age) and prints a string composed value.
Formatting should be: «Hello, my name is FIRSTNAME LASTNAME, I'm AGE.»
Make sure you are printing a newline.
/*
**
** QWASAR.IO — my_string_formatting
**
**
** @param {String} param_1
** @param {String} param_2
** @param {Integer} param_3
**
*/

function my_string_formatting(param_1, param_2, param_3) {

};
Example 00

Input: «john» && «doe» && 37
Output: Hello, my name is john doe, I'm 37.

Return Value: nil
Example 01

Input: «Baby» && «Yoda» && 50
Output: Hello, my name is Baby Yoda, I'm 50.

Return Value: nil
Example 02

Input: «Marie» && «Curie» && 26
Output: Hello, my name is Marie Curie, I'm 26.

Return Value: nil
Александр Мальцев
Александр Мальцев
Привет! Тут вроде всё просто:
function my_string_formatting(param_1, param_2, param_3) {
  console.log('Hello, my name is ' + param_1 + ' ' + param_2 + ', I\'m ' + param_3 + '.');
}
Катя
Катя
Доброго дня Олександр.
Дякую за цікаві матеріали та можливість навчання.
Допоможіть будь ласка з таким завданням:
Створи функцію greeter, яка приймає параметр name.
Використовуючи параметр name, поверни з функції рядок-привітання такого формату: Hi, ${name}!..
Результатом має бути два імені Mike, luis.
Не розумію де маю прописати ці імена в коді.
Мій варіант коду:
function greeter ('name') {
console.log(«Hi,» + $(name));
return name;
}
Дякую.
Александр Мальцев
Александр Мальцев
Привет!
Я это задание понимаю так:
function greeter(name) {
  return `Hi, ${name}`;
}

console.log(greeter('Mike'));
console.log(greeter('Iuis'));
Катя
Катя
Ура :), працює.
Дякую.
Vadim
Vadim
Добрый день!
Есть задачка
Создай функцию double, которая принимает число num и возвращает его удвоенное значение, например:

double (5) возвращает 10,
double (24) возвращает 48.

прописываю
const double = (num) => (`2 * ${num}`);
в описании ошибки выдает
Function 'double' should return result of type number

подскажите в чем ошибка?
спасибо
Александр Мальцев
Александр Мальцев
Добрый день! Использовать обратный апостроф не нужно:
const double = (num) => 2 * num;
Vadim
Vadim
спасибо

а в этом случае?

Создай функцию multiply, которая принимает 2 параметра a и b типа number, и возвращает произведение двух чисел. Параметр b должен иметь значение по умолчанию — 1.

пример:

multiply (10, 2) возвращает 20;
multiply (10) возвращает 10,
Александр Мальцев
Александр Мальцев
Тут всё просто:
const multiply = (a, b = 1) => a * b;
Ekaterina
Ekaterina
Здравствуйте, Александр!
Проконсультируйте, пожалуйста, по решению задачи:
Напишите функцию, которая принимает объект с полем name и возвращает 0 если длина этого поля четная и 1 если нечетная
ПРИМЕРЫ:
Input: {name: 'abra'}
Actions:
Output: 0
Input: {name: 'cadabra'}
Actions:
Output: 1

Мое решение:
function test(obj) {
if (obj.length === 1) {
return 1
} else {
return 0
}
}

Пишет ошибку: [4:10] Unnecessary 'else' after 'return'.

Александр Мальцев
Александр Мальцев
Здравствуйте! Так вам нужно сначала получить длину значения свойства «name» переданного объекта, а затем вычислить остаток от деления 2. И если он будет равен 0, то вернуть 0. В противном случае 1.
function test(obj) {
  if (obj['name'].length % 2 === 0) {
    return 0;
  } else {
    return 1;
  }
}
Ekaterina
Ekaterina
Выдал ошибку, что Name лучше писать через точки, я исправила.
Пишет, что лишний else. [4:10] Unnecessary 'else' after 'return'.
Как правильно его убрать?
function test(obj) {
if (obj.name.length % 2 === 0) {
return 0;
} else {
return 1;
}
}
Александр Мальцев
Александр Мальцев
Можно без else:
function test(obj) {
  if (obj['name'].length % 2 === 0) {
    return 0;
  }
  return 1;
}
Ekaterina
Ekaterina
Получилось! Спасибо большое!
Navolokin Roman
Navolokin Roman
const greeter = (name = '', partOfDay = '') => ('Good' + partOfDay + ", " + name + "!");

Она возвращает строку «Goodmorning, Mike!»

а должна возвращать «Good morning, Mike!» — как сделать этот пробел между Good и morning?
Александр Мальцев
Александр Мальцев
Так нужно просто добавить пробел в конце строки 'Good':
const greeter = (name = '', partOfDay = '') => ('Good ' + partOfDay + ', ' + name + '!');
Navolokin Roman
Navolokin Roman
Объяви функцию-стрелку getString. Объяви внутри функции переменную randomString с любым значением типа string и верни ее, используя ключевое слово return.

function getString(){
const randomString = 'Name';
return randomString;
}

как переделать ее в стрелочную функцию, подскажите
Александр Мальцев
Александр Мальцев
Будет так:
const getString = () => {
  const randomString = 'Name';
  return randomString;
};
Navolokin Roman
Navolokin Roman
Спасибо Вам огромное!
Navolokin Roman
Navolokin Roman
Стрелочные функции используются просто для сокращения кода?
Александр Мальцев
Александр Мальцев
Современный синтаксис для написания функций.
Alex
Alex
Здраствуйте!
Помогите написать код на js:

Объяви функцию getString, что возвращает любое значение типа string. Объяви переменную getStringResult и присвоить ей результат вызова функции getString.
Александр Мальцев
Александр Мальцев
Здравствуйте!
Решение этой задачи:
function getString() {
  return 'Привет';
}
const getStringResult = getString();
Alex
Alex
Спасибо огромное!
Ekaterina
Ekaterina
Благодарю Вас!
Ekaterina
Ekaterina
Здравствуйте, Александр!
Подскажите, пожалуйста, если нужно написать функцию, которая преобразует имя и фамилию в шаблон My Name Is: $Name $Surname, как это сделать без объявления переменной, то есть сразу вернуть результат?
1. Function test(name, surname) {
2. return
3. }
Александр Мальцев
Александр Мальцев
Здравствуйте!
Будет так:
function test(name, surname) {
  return 'My Name Is: ' + name + ' ' + surname;
}
Используя современный синтаксис так:
let test = (name, surname) => `My Name Is: ${name} ${surname}`;
Использовать функцию так (например, вывести результат в консоль):
console.log(test('John', 'Lennon'));
Gregory
Gregory
Можно получить параметры передаваемые в скобках если это предусмотреть внутри самой функции)