Задачи по JavaScript для начинающих от Tproger и GeekBrains
Вместе с факультетом Веб-разработки GeekUniversity собрали для вас несколько простых задач по JavaScript для обучения и тренировки, а также пару теоретических вопросов. Задачи расположены в порядке возрастания сложности.
Обратите внимание, что у любой задачи по программированию может быть несколько способов решения. Чтобы посмотреть добавленный нами вариант решения, кликните по соответствующей кнопке.
***
Задача 1
Напишите однострочное решение, которое вычисляет сумму квадратных корней для всех чётных чисел целочисленного массива.
Вариант решения
console.log( // Входной массив [1, 4, 3, 0, 4, 5, 4] // Оставляем только чётные числа .filter(element => !(element % 2)) // Считаем квадратный корень и записываем в аккумулятор .reduceRight((accumulator, element) => accumulator + Math.sqrt(element), 0) ); // 6
Метод reduceRight()
применяет функцию к аккумулятору и каждому значению массива (справа налево), сводя его к одному значению. А метод reduce()
выполняет функцию callback
один раз для каждого элемента, присутствующего в массиве, за исключением пустот, принимая четыре аргумента:
- начальное значение (или значение от предыдущего вызова
callback
); - значение текущего элемента;
- текущий индекс;
- массив, по которому происходит итерация.
Задача 2
Напишите функцию, которая пишет в консоль число в заданном диапазоне, в случае, если оно успешно делится или не делится с остатком или без остатка в зависимости от параметров.
Вариант решения
function getNumbersModulatordBy(modulus, loggerCallback) { // Функция, которая возвращает функцию - это подход из функционального программирования // Называется замыканием (Closure) return function(start, end) { loggerCallback({ message: "Конфигурация", config: configuration }); loggerCallback({ message: "Полученный модулятор", modulus: modulus }); loggerCallback({ message: "Полученный start и end", start: start, end: end }); while (start <= end) { // Стоит обратить внимание: // 1. При нестрогом равенстве true == 1 и false == 0 // 2. Здесь мы обращаемся к глобальному контексту configuration // p.s. поле isEntry может меняться if (start % modulus == configuration.isEntry) { // В данном случае мы используем loggerCallback как middleware // Это определит дальнейшую судьбу результата // Позволяет убрать side-effect loggerCallback(start); } start++; } }; } // Глобальный контекст не имеет блочной видимости // В данном случае переменная поднимается выше в самое начало кода // Исполнитель JavaScript видит её в независимости от места инициализации var configuration = { modulus: 10, isEntry: false, start: 45, end: 68 }; var loggerCallback = data => console.log(data); let tenNumbersModulator = getNumbersModulatordBy( configuration.modulus, loggerCallback ); // Переменные с глобальным контекстом доступны из: // 1. globalThis (в Node.js) // 2. window (в браузере) window.configuration.modulus = 5; let fiveNumbersModulator = getNumbersModulatordBy( configuration.modulus, loggerCallback ); tenNumbersModulator(configuration.start, configuration.end); // 50, 60 tenNumbersModulator(10, 100); // 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 // Так как мы изменили поле isEntry, то теперь: // Функция вернёт те значения, которые не входят в модуляцию числа window.configuration.isEntry = true; fiveNumbersModulator(configuration.start, configuration.end); // 46, 51, 56, 61, 66 fiveNumbersModulator(10, 21); // 11, 16, 21
Задача 3
Есть ферма животных, у всех животных есть имена и возраст. Животные бывают разных типов: Кошки, Собаки, Коровы. У каждого животного могут быть дети. Если животное является родителем этих детей, в свою очередь глубина семейного древа может достигать N
либо 0
.
Опишите структуры данных для фермы животных и напишите функцию, которая делает подсчёт всех возрастов животных и выводит общий возраст для всей фермы.
Вариант решения
// Родительский класс для всех животных class Animal { constructor(name, age, childs = null) { this.name = name; this.age = age; this.childs = childs; } } // Класс Cat - потомок класса Animal // Имеет те же поля, что и Animal class Cat extends Animal { constructor(name, age, childs = null) { super(name, age, childs); } } // Класс Dog - потомок класса Animal // Имеет те же поля, что и Animal class Dog extends Animal { constructor(name, age, childs = null) { super(name, age, childs); } } // Класс Cow - потомок класса Animal // Имеет те же поля, что и Animal class Cow extends Animal { constructor(name, age, childs = null) { super(name, age, childs); } } // Рекурсивная функция для подсчета age // Обходит все дочерние элементы function getAnimalsAge(animals) { let output = 0; if (animals.length > 0) { // Использование функции reduce для получения общего age // https://learn.javascript.ru/array-iteration output += animals.reduce((acc, current) => { // Сумма age всех childs let count = 0; // Если childs пустой или его нет, тогда нет смысла пробегать по ним if (current.childs && current.childs.length > 0) { // Применение рекурсии count += getAnimalsAge(current.childs); } // Возвращаем сумму аккумулятора, текущего животного, сумму age всех childs return acc + current.age + count; }, 0); } return output; } // Функция для получения определённого количества животных function generateAnimals(type, count) { let output = []; for (let i = 0; i <= count; i++) { let parameter = { name: `${type} ${i}`, age: i, childs: [] }; let item = null; switch (type) { case "Cat": item = new Cat(parameter.name, parameter.age); break; case "Dog": item = new Dog(parameter.name, parameter.age); break; case "Cow": item = new Cow(parameter.name, parameter.age); break; } if (item) { output.push(item); } } return output; } // Добавление childs ко всем переданным животным function addChildsTo(animals, count, type) { animals.forEach(animal => { if (!animal.childs) { animal.childs = []; } // Обратите внимание, что массив - ссылка, поэтому изменяя здесь его поля // мы меняем их глобально animal.childs = generateAnimals(type, count); }); } let cats = generateAnimals("Cat", 5); addChildsTo(cats, 10, "Cat"); let dogs = generateAnimals("Dog", 3); addChildsTo(dogs, 3, "Dog"); let cows = generateAnimals("Cow", 7); addChildsTo(cows, 1, "Dog"); // Использование оператора Spread (ES6) // https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Spread_syntax let animals = [...cats, ...dogs, ...cows]; console.log(getAnimalsAge(animals)) // 411
Задача 4
Перепишите функцию clone
таким образом, чтобы она была способна клонировать переданный как параметр объект.
Пример проблемы:
let animal = { name: "animal", age: 10, childs: ["child 1", "child 2"] }; let cat = clone(animal); cat.name = "cat"; cat.age = 5; cat.childs.push("child 3"); console.log(cat.name, cat.age); // cat 5 console.log(cat.childs); // [ 'child 1', 'child 2', 'child 3' ] console.log(animal.name, animal.age); // cat 5 console.log(animal.childs); // [ 'child 1', 'child 2', 'child 3' ] function clone(obj) { return obj; }
Варианты решения
Deep copy (глубокое копирование)
console.log(cat.name, cat.age); // cat 5 console.log(cat.childs); // [ 'child 1', 'child 2', 'child 3' ] console.log(animal.name, animal.age); // animal 10 console.log(animal.childs); // [ 'child 1', 'child 2' ] // Отличный вариант для JSON-safe объектов let clone = (obj) => JSON.parse(JSON.stringify(obj)); // Опасен для рекурсивных объектов или когда имеется конструктор с параметрами let clone = obj => { if (obj === null || typeof obj !== "object" || "isActiveClone" in obj) return obj; if (obj instanceof Date) var temp = new obj.constructor(); //or new Date(obj); else var temp = obj.constructor(); for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { obj["isActiveClone"] = null; temp[key] = clone(obj[key]); delete obj["isActiveClone"]; } } return temp; };
Experimental deep copy (экспериментальное глубокое копирование)
Как пишут на Stack Overflow, HTML-стандарт включает в себя алгоритм структурированного клонирования, который может создавать глубокие копии объектов. Он всё ещё ограничен встроенными типами, но в дополнение к тем типам, что поддерживаются в JSON, поддерживает Dates, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, Sparse Arrays, Typed Arrays и, вероятно, больше в будущем. Решает также проблемы цикличных и рекурсивных структур, которые ломают JSON.
console.log(cat.name, cat.age); // cat 5 console.log(cat.childs); // [ 'child 1', 'child 2', 'child 3' ] console.log(animal.name, animal.age); // animal 10 console.log(animal.childs); // [ 'child 1', 'child 2' ] let clone = (obj) => require("v8").deserialize(require("v8").serialize(obj));
Shallow copy (поверхностное копирование)
Клонирование вложенных свойств по ссылке пропускается, нужно быть осторожным в использовании.
console.log(cat.name, cat.age); // cat 5 console.log(cat.childs); // [ 'child 1', 'child 2', 'child 3' ] console.log(animal.name, animal.age); // animal 10 console.log(animal.childs); // [ 'child 1', 'child 2', 'child 3' ] // Копирует значение всех собственных итерируемых элементов объекта let clone = (obj) => Object.assign(new Object(), obj); // Более известен как оператор Spread let clone = (obj) => { ...obj };
Задача 5
Выйдите из цикла, изменив только две отмеченные строки. Результат в консоли сейчас останавливается на 9 9
. Должен на 5 4
.
for (let i = 0; i < 10; i++) { //! Эту строку можно изменить for (let j = 0; j < 10; j++) { if (i === 5 && j === 5) { //! Эту строку можно изменить } console.log(i, j); } }
Вариант решения
Как пишут на MDN web docs, инструкция метки (label) используется вместе с break
или continue
для альтернативного выхода из цикла. Метка добавляется перед блочным выражением в качестве ссылки, которая может быть использована в дальнейшем.
cycle: for (let i = 0; i < 10; i++) { //! Эту строку можно изменить for (let j = 0; j < 10; j++) { if (i === 5 && j === 5) { break cycle; //! Эту строку можно изменить } console.log(i, j); } }
Задача 6
Яблоко стоит 1.15, апельсин стоит 2.30. Сколько они стоят вместе – чему равна сумма 1.15 + 2.30 с точки зрения JavaScript?
Ответ
3.4499999999999997
Число хранится в памяти в бинарной форме, как последовательность бит – единиц и нулей. Но дроби, такие как 1.15, 2.30, которые выглядят довольно просто в десятичной системе счисления, на самом деле являются бесконечной дробью в двоичной форме. Это объяснение взято с сайта Современный учебник JavaScript, там же можно подробно почитать про числа в языке.
Задача 7
Чему равен typeof null
в режиме use strict
?
Ответ
object
Как пишут на Хабре:
Все JavaScript-программисты давно привыкли к тому, что
typeof null === 'object'; // true
, хотя фактически null — примитивное значение. Многие знают, что это баг, и лично Брэндан Айк это признаёт. Этот баг, вероятно, никогда не будет исправлен из-за необходимости сохранения обратной совместимости существующего кода с новыми версиями языка.
Хотите вырасти от новичка до профессионала? Факультет Веб-разработки GeekUniversity даёт полтора года опыта для вашего резюме. Обучайтесь на практических заданиях, по-настоящему освойте фулстек-разработку и станьте ближе к профессии мечты.
Узнать больше
- 136 views
- 0 Comment