• stackdev.blog articles

    Василий Муравьев

  • Мои Курсы8
  • Youtube
  • Telegram
  • Контакты

Задачи по JavaScript для начинающих (6 задач + решение)

Дата: 10.10.2023
Javascript

В этой статье мы рассмотрим 6 популярных задач по JavaScript для начинающих, которые частенько встречаются на собеседованиях на позицию Junior Frontend разработчика.

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

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

Задача 1. Определить сколько раз каждый элемент встречается в массиве.

Имеется исходный массив:

1const fruits = ['kiwi', 'apple', 'kiwi', 'orange', 'kiwi', 'apple'];

Требуется получить ответ в следующем формате:

1// {kiwi: 3, apple: 2, orange: 1}

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

1const count = {};

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

Если текущий элемент в объекте отсутсвует, то добавляем этот элемент со значением 1. В противном случае также добавляем элемент в объект, но его текущее значение увеличиваем на 1.

1const fruits = ['kiwi', 'apple', 'kiwi', 'orange', 'kiwi', 'apple'];
2
3const count = {};
4
5fruits.forEach(f => {
6
7 if (!count[f]) {
8 // Текущий элемент отсутствует в объекте count
9 count[f] = 1;
10
11 } else {
12 // Текущий элемент ранее был добавлен в объект count
13 count[f] ++;
14 }
15});

Проверяем значение переменной count:

1console.log(count);
2// Object { kiwi: 3, apple: 2, orange: 1 }

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

1const countItems = (list) => {
2 const count = {};
3
4 list.forEach(f => {
5 if (!count[f]) {
6 count[f] = 1;
7 } else {
8 count[f] ++;
9 }
10 });
11
12 return count;
13};

Таким образом, мы можем получать результат подсчета количества каждого элемента в любом массиве следующим образом:

1const countResult = countItems(fruits);
2
3console.log(countResult);
4// {kiwi: 3, apple: 2, orange: 1}

Задача 2. Создать массив который содержит только уникальные значения исходного массива.

Исходный массив:

1const fruits = ['kiwi', 'apple', 'kiwi', 'orange', 'kiwi', 'apple'];

Давайте рассмотрив 2 возможных решения этой задачи.

Задача 2. Вариант 1. Используем конструктор Set.

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

1const fruitsUnique = new Set(fruits);
2// Set(3) [ "kiwi", "apple", "orange" ]

На выходе мы получили так называемый Set (коллекция) из 3-х уникальных значений. Чтобы получить массив мы можем обернуть наш результат в метод Array.from().

1const fruitsUnique = Array.from(new Set(fruits));
2// Array(3) [ "kiwi", "apple", "orange" ]

Задача 2. Вариант 2. Используем пустой объект и цикл forEach.

На одном из собеседований меня попросили создать массив из уникальных значений, без использования конструктора Set.

Один из вариантов, как это можно сделать - использовать метод forEach и последовательно добавлять каждый элемент массива в пустой объект с произвольным значением (например true):

1const myFruits = ['kiwi', 'apple', 'kiwi', 'orange', 'kiwi', 'apple'];
2
3 const unique = {};
4
5 myFruits.forEach(item => {
6 unique[item] = true;
7 });

Каждый, повторно встречающийся, элемент перезаписывается внутри объекта unique последним значением. Таким образом, наш объект unique содержит только уникальные названия ключей.

1console.log(unique);
2// Object { kiwi: true, apple: true, orange: true }

Чтобы получить массив из ключей объекта можно использовать метод Object.keys():

1const myFruits = ['kiwi', 'apple', 'kiwi', 'orange', 'kiwi', 'apple'];
2
3 const unique = {};
4
5 myFruits.forEach(item => {
6 unique[item] = true;
7 });
8
9// Получаем массив из уникальных ключей
10const uniqueArray = Object.keys(unique);
11
12console.log( uniqueArray);
13// Array(3) [ "kiwi", "apple", "orange" ];

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

1const uniqueItems = (list) => {
2 const unique = {};
3
4 list.forEach(item => {
5 unique[item] = true;
6 });
7
8 return Object.keys(unique);
9}

Таким образом мы можем повторно использовать нашу новую функцию uniqueItems в разных частях нашего кода с разными исходными массивами:

1const fruits = ['kiwi', 'apple', 'kiwi', 'orange', 'kiwi', 'apple'];
2
3const fruitsUnique = uniqueItems(fruits);
4
5console.log(fruitsUnique);
6// Array(3) [ "kiwi", "apple", "orange" ];

Задача 3. Создать функцию, которая группирует студентов по возрасту.

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

Исходный массив:

1const students = [
2 { name: 'alex', age: 20 },
3 { name: 'mike', age: 24 },
4 { name: 'masha', age: 20 },
5 { name: 'stas', age: 18 },
6];

Требуется получить ответ в следующем формате:

1// '20': [{ name: 'alex', age: 20 }, { name: 'masha', age: 20 }],
2// '24': [{ name: 'mike', age: 24 }],
3// '18': [{ name: 'stas', age: 18 }],

Эту задачку мы также можем решить, используя цикл forEach и пустой объект, в который будем добавлять каждый элемент массива (студент). В качестве ключа будем использовать возраст.

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

1const students = [
2 { name: 'alex', age: 20 },
3 { name: 'mike', age: 24 },
4 { name: 'masha', age: 20 },
5 { name: 'stas', age: 18 },
6];
7
8const grouped = {};
9
10students.forEach(s => {
11
12 if (!grouped[s.age]) {
13 // Ключ с возрастом отсутствует
14 grouped[s.age] = [s];
15
16} else {
17 grouped[s.age].push(s);
18 }
19});

Если ключ (s.age) отсутствует, то добавляем его в объект grouped. В этом случае значением ключа будет объект текущего студента (переменная s) в массиве [s].

Если ключ ранее уже был добавлен в объект, то значение ключа уже содержит массив, в который нам остается добавить текущий объект студента с помощью метода push.

Задача 4.

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

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

Итак, у нас есть исходный массив myNumbers и целое число sum:

1const myNumbers = [3, 5, -4, 8, 11, 1, -1, 6];
2const sum = 10;

Результат работы нашей функции должен иметь следующий формат:

1// [-1, 11] или [11, -1] - так как -1 + 11 = 10;

Наша итоговая функция может выглядеть следующим образом:

1const findPairs = (nums, target) => {
2
3 // Основной цикл
4 for (let i = 0; i < nums.length; i++) {
5 const numFirst = nums[i];
6
7 // Вложенный цикл
8 for (let j = i + 1; j < nums.length; j++) {
9 const numSecond = nums[j];
10
11 // Условие
12 if (numFirst + numSecond === target) {
13
14 // Условие выполняется
15 return [numFirst, numSecond];
16 }
17 }
18 }
19
20 // Условие не выполняется
21 return [];
22}

Наша функция findPairs принимает на вход массив nums и целое число target.

Внутри функции мы создаем основной цикл, с помощью которого "бежим" по каждому элементу массива nums, ничаная с 1-го элемента (индекс i = 0). Внутри основного цикла записываем последовательно каждый элемент массива nums в переменную numFirst.

Чтобы для каждого значения, которое мы записываем в переменную numFirst получать следующий за ним элемент массива, запускаем вложенный цикл. Этот цикл "стартует" со 2-го элемента массива nums (индекс j = i + 1).

Внутри вложенного цикла записываем каждое значение в переменную numSecond.

Далее, внутри вложенного цикла проверяем, равняется ли сумма numFirst и numSecond переменной target.

Если условие выполняется, возвращаем значения numFirst и numSecond внутри новго массива. В противном случае функция возвращает пустой массив.

Запускаем функцию и выводим в лог результат:

1const result = findPairs(myNumbers, sum);
2
3console.log(result);
4// Array [ 11, -1 ]

Задача 5. Получить единый массив из любимых пицц каждого друга

Имеется исходный массив friends:

1const friends = [
2 { name: 'alex', pizzas: ['cheese', 'pepperoni'] },
3 { name: 'mike', pizzas: ['salami', 'margarita'] },
4 { name: 'stas', pizzas: ['meat'] },
5 { name: 'anna', pizzas: ['fish'] }
6];

Нужно получить результат в следующем формате:

1// ['cheese', 'pepperoni', 'salami', 'margarita', 'meat', 'fish'];

Для решения этой задачи можем использовать метод reduce:

1const pizzas = friends.reduce((accum, current) => {
2 return [...accum, ...current.pizzas];
3}, []);

На старте, указываем, что начальное значение переменной accum - пустой массив []. Далее, последовательно "бежим" по каждому элементу массива и каждый раз возвращаем обновленное значение accum.

Обновленное значение accum это - массив, в который при каждой итерации добавляются:

  1. Все текущие элементы переменной accum, которые были добавлены в предыдущей итерации
  2. Все пиццы из текущего элемента массива в переменной current: current.pizzas

Получаем результат и выводим его в лог:

1console.log(pizzas);
2// Array(6) [ "cheese", "pepperoni", "salami", "margarita", "meat", "fish" ]

Задача 6. Записать строку (символы строки) в обратном порядке

Наше исходное строковое значение:

1const myStr = 'pizza';

От нас требуется получить строковое значение pizza, записанное в обратном порядке:

1// azzip

Давайте рассмотрим 2 варианта записи строковых значений в обратном порядке.

Задача 6. Вариант 1 - используем цикл

1const myStr = 'pizza';
2
3const reverseString = (str) => {
4 const reversed = [];
5
6 for (let i = str.length - 1; i >= 0; i--) {
7 reversed.push(str[i]);
8 };
9
10 return reversed.join('');
11};

Создаем функцию reverseString, которая на вход принимает строковое значение в переменной str. Далее создаем цикл, который итерирует каждый символ строки в обратном порядке, начиная с последнего элемента (индекс i = str.length - 1).

При итерации каждый символ переменной str последовательно добавляется в новый пустой массив reversed. После окончания работы цикла, массив reversed трансформируется в строковое значение, используя метод .join().

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

1const reverseResult = reverseString(myStr);
2
3console.log(reverseResult);
4// azzip

Задача 6. Вариант 2 - используем метод .split() и .reverse()

Чтобы записать строку в обратном порядке мы также можем использовать методы .split() и .reverse().

1const reverseString2 = (str) => {
2 return str.split('').reverse().join('');
3};

Используя этот вариант, мы сначала используем метод .split(), чтобы создать массив из строчного значения в переменной str. Даллее, по цепочке применяем к полученному массиву 2 метода:

  1. Метод .reverse, который меняет порядок элементов в массиве в обратном направлении (Записывает первый элемент последним, а последний — первым).
  2. Метод .join, который объединяет элементы массива в строку. В методе .join() указывается разделитель, который будет вставлен между элементами. В нашем случае - указываем пустые ковычки .join('').
Вперед →

Типы данных в JavaScript (8 типов + примеры)

Популярные статьи

  • Задачи JavaScript для начинающих
  • Типы данных в JavaScript
  • Как проверить объект JavaScript на пустоту?
  • Обработчики Событий в JS
  • Деструктуризация в Javascript
  • Массивы Javascript: перебирающие методы
  • Операторы Spread и Rest в Javascript
  • Объект Date: Текущая Дата и Время в Javascript
  • Переменные JavaScript var, let и const
© 2023 StackDev.Blog