Share This
Связаться со мной
Крути в низ
Categories
//Задачи по JavaScript для начинающих от Tproger и GeekBrains

Задачи по 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

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Связаться со мной
Close