diff --git a/projects/array-objects/index.js b/projects/array-objects/index.js new file mode 100644 index 000000000..3915a2134 --- /dev/null +++ b/projects/array-objects/index.js @@ -0,0 +1,82 @@ +/* ДЗ 2 - работа с массивами и объектами */ + +/* + Задание 1: + + Напишите аналог встроенного метода forEach для работы с массивами. + Посмотрите как работает forEach и повторите это поведение для массива, который будет передан в параметре array + + Пример: + forEach([1, 2, 3], (el) => console.log(el)); // выведет каждый элемент массива + */ + function forEach(arr,el) { + for (let i = 0; i < arr.length; i++) { + el(arr[i],i,arr) + } + } + forEach([1, 2, 3],el=(item,index,array)=>{console.log(item,index,array)}); + +/* + Задание 2: + + Напишите аналог встроенного метода map для работы с массивами. + Посмотрите как работает map и повторите это поведение для массива, который будет передан в параметре array + + Пример: + const newArray = map([1, 2, 3], (el) => el ** 2); + console.log(newArray); // выведет [1, 4, 9] + */ + function map (arr,callback) { + let newArray = [] + for(let i = 0; i < arr.length ; i++){ + newArray[i] = callback(arr[i],i,arr) + } + return newArray + } + const newArray = map([10,20,30],function callback (item,index,array){return item ** 2 }) + +/* + Задание 3: + + Напишите аналог встроенного метода reduce для работы с массивами. + Посмотрите как работает reduce и повторите это поведение для массива, который будет передан в параметре array + + Пример: + const sum = reduce([1, 2, 3], (all, current) => all + current); + console.log(sum); // выведет 6 + */ + function reduce(arr,callback,initialValue) { + let result = 0 + let i = 0 + if ( arguments.length > 2){ + result = initialValue + }else{result = arr[0],i=1} + + for (; i < arr.length ; i++){ + result = callback(result,arr[i],i,arr) + } + return result + } + + let result = reduce ([1,2,3], function callback (accumulator,currentValue,index,array){return accumulator + currentValue}) + +/* + Задание 4: + + Функция должна перебрать все свойства объекта, преобразовать их имена в верхний регистр и вернуть в виде массива + + Пример: + const keys = upperProps({ name: 'Сергей', lastName: 'Петров' }); + console.log(keys) // выведет ['NAME', 'LASTNAME'] + */ + function upperProps(obj) { + let result = [] + for (let key in obj) { + let upper = key.toUpperCase() + result.push(upper) + } + return result + } + const keys = upperProps ({name:'Сергей', lastName:'Петров'}) + +export { forEach, map, reduce, upperProps }; diff --git a/projects/array-objects/index.spec.js b/projects/array-objects/index.spec.js new file mode 100644 index 000000000..eddc0bfdc --- /dev/null +++ b/projects/array-objects/index.spec.js @@ -0,0 +1,78 @@ +import { forEach, map, reduce, upperProps } from './index'; + +describe('ДЗ 3 - объекты и массивы', () => { + describe('forEach', () => { + it('должна вызывать функцию для каждого элемента массива', () => { + const array = [1, 2, 3]; + const fn = jest.fn(); + + forEach(array, fn); + + for (let i = 0; i < array.length; i++) { + expect(fn).nthCalledWith(i + 1, array[i], i, array); + } + }); + }); + + describe('map', () => { + it('должна вызывать функцию для каждого элемента массива и не изменять оригинальный массив', () => { + const originalArray = [4, 5, 6]; + const array = [...originalArray]; + const modified = array.map((el) => el ** 2); + const fn = jest.fn((el) => el ** 2); + + expect(map(array, fn)).toEqual(modified); + expect(array).toEqual(originalArray); + + for (let i = 0; i < array.length; i++) { + expect(fn).nthCalledWith(i + 1, array[i], i, array); + } + }); + }); + + describe('reduce', () => { + it('должна вызывать функцию для каждого элемента и передавать предыдущий результат первым аргументом', () => { + const originalArray = [7, 8, 9]; + const array = [...originalArray]; + const modified = array.reduce((all, current) => all + current); + const fn = jest.fn((all, current) => all + current); + + expect(reduce(array, fn)).toEqual(modified); + expect(array).toEqual(originalArray); + + let sum = array[0]; + + for (let i = 1; i < array.length; i++) { + expect(fn).nthCalledWith(i, sum, array[i], i, array); + sum += array[i]; + } + }); + + it('должна учитывать initial', () => { + const originalArray = [1, 3, 5]; + const array = [...originalArray]; + const modified = array.reduce((all, current) => all + current, 10); + const fn = jest.fn((all, current) => all + current); + + expect(reduce(array, fn, 10)).toEqual(modified); + expect(array).toEqual(originalArray); + + let sum = 10; + + for (let i = 0; i < array.length; i++) { + expect(fn).nthCalledWith(i + 1, sum, array[i], i, array); + sum += array[i]; + } + }); + }); + + describe('upperProps', () => { + it('должна возвращать массив с именами свойств и преобразовывать эти имена в верхний регистр', () => { + const obj = { a: 1, b: 2 }; + const target = ['A', 'B']; + const result = upperProps(obj); + + expect(result).toEqual(target); + }); + }); +}); diff --git a/projects/exceptions/index.js b/projects/exceptions/index.js new file mode 100644 index 000000000..a67f76b61 --- /dev/null +++ b/projects/exceptions/index.js @@ -0,0 +1,158 @@ +/* ДЗ 3 - работа с исключениями и отладчиком */ + +/* + Задание 1: + + 1.1: Функция isAllTrue принимает массив в параметре array и другую функцию в параметре fn. + Нужно по-очереди запустить функцию fn для всех элементов массива. + isAllTrue должна вернуть true только если fn вернула true для всех элементов массива. + Если хотя бы для одного из элементов массива fn вернула false, то и isAllTrue должна вернуть false. + + 1.2: Необходимо выбрасывать исключение в случаях: + - array не массив или пустой массив (с текстом "empty array") + для проверки на массив вам может помочь функция Array.isArray() + - fn не является функцией (с текстом "fn is not a function") + для проверки на функцию вам может помочь оператор typeof + + Запрещено использовать встроенные методы для работы с массивами + + Пример: + isAllTrue([1, 2, 3, 4, 5], n => n < 10) // вернет true (потому что все элементы массива меньше 10) + isAllTrue([100, 2, 3, 4, 5], n => n < 10) // вернет false (потому что как минимум первый элемент больше 10) + */ +function isAllTrue(array, fn) { + if (!Array.isArray(array) || array.length === 0) { + throw new Error('empty array'); + } + + if (typeof fn !== 'function') { + throw new Error('fn is not a function'); + } + + for (const n of array) { + if (!fn(n)) { + return false; + } + } + return true; +} +isAllTrue([1, 2, 3], (n) => n < 10); +/* + Задание 2: + + 2.1: Функция isSomeTrue принимает массив в параметре array и функцию в параметре fn. + Нужно по-очереди запустить функцию fn для всех элементов массива. + isSomeTrue должна вернуть true только если fn вернула true хотя бы для одного из элементов массива. + Если fn не вернула true ни для одного элементов массива, то и isSomeTrue должна вернуть false. + + 2.2: Необходимо выбрасывать исключение в случаях: + - array не массив или пустой массив (с текстом "empty array") + для проверки на массив вам может помочь функция Array.isArray() + - fn не является функцией (с текстом "fn is not a function") + для проверки на функцию вам может помочь оператор typeof + + Запрещено использовать встроенные методы для работы с массивами + + Пример: + isSomeTrue([1, 2, 30, 4, 5], n => n > 20) // вернет true (потому что в массиве есть хотя бы один элемент больше 20) + isSomeTrue([1, 2, 3, 4, 5], n => n > 20) // вернет false (потому что в массиве нет ни одного элемента больше 20) + */ +function isSomeTrue(array, fn) { + if (!Array.isArray(array) || array.length === 0) { + throw new Error('empty array'); + } + + if (typeof fn !== 'function') { + throw new Error('fn is not a function'); + } + + for (const n of array) { + if (!fn(n)) { + return false; + } + } + return true; +} +console.log(isSomeTrue([1, 2, 3], (n) => n < 10)); + +/* + Задание 3: + + 3.1: Функция returnBadArguments принимает заранее неизвестное количество аргументов, первым из которых является функция fn + returnBadArguments должна поочередно запустить fn для каждого переданного аргумента (кроме самой fn) + + 3.2: returnBadArguments должна вернуть массив аргументов, для которых fn выбросила исключение + + 3.3: Необходимо выбрасывать исключение в случаях: + - fn не является функцией (с текстом "fn is not a function") + для проверки на функцию вам может помочь оператор typeof + */ +let a = 1; +let b = 2; +function returnBadArguments(fn, ...args) { + if (typeof fn !== 'function') { + throw new Error('fn is not a function'); + } + const badArgs = []; + for (const arg of args) { + try { + fn(arg); + } catch { + badArgs.push(arg); + } + } + return badArgs; +} +console.log(returnBadArguments((f) => arg, a, b)); + +/* + Задание 4: + + 4.1: Функция calculator имеет параметр number (по умолчанию - 0) + + 4.2: Функция calculator должна вернуть объект, у которого должно быть несколько методов: + - sum - складывает number с переданными аргументами + - dif - вычитает из number переданные аргументы + - div - делит number на первый аргумент. Результат делится на следующий аргумент (если передан) и так далее + - mul - умножает number на первый аргумент. Результат умножается на следующий аргумент (если передан) и так далее + + Количество передаваемых в методы аргументов заранее неизвестно + + 4.3: Необходимо выбрасывать исключение в случаях: + - number не является числом (с текстом "number is not a number") + - какой-либо из аргументов div является нулем (с текстом "division by 0") + + Пример: + const myCalc = calculator(10); + + console.log(calc.sum(1, 2, 3)); // выведет 16 (10 + 1 + 2 + 3) + console.log(calc.dif(1, 2, 3)); // выведет 5 (10 - 1 - 2 - 3) + console.log(calc.mul(1, 2, 3)); // выведет 60 (10 * 1 * 2 * 3) + console.log(calc.div(2, 2)); // выведет 2.5 (10 / 2 / 2) + console.log(calc.div(2, 0)); // выбросит исключение, потому что один из аргументов равен 0 + */ +function calculator(number=0, ...args) { + if (typeof number !== 'number') { + throw new Error('number is not a number'); + } + return { + sum(...args) { + return args.reduce((all, current) => all + current, number); + }, + dif(...args) { + return args.reduce((all, current) => all - current, number); + }, + div(...args) { + if ((args.some((a) => a === 0))) { + throw new Error('division by 0'); + } + return args.reduce((all, current) => all / current, number); + }, + mul(...args) { + return args.reduce((all, current) => all * current, number); + }, + }; +} +/* При решении задач, постарайтесь использовать отладчик */ + +export { isAllTrue, isSomeTrue, returnBadArguments, calculator }; diff --git a/projects/exceptions/index.spec.js b/projects/exceptions/index.spec.js new file mode 100644 index 000000000..bb9b4d0c1 --- /dev/null +++ b/projects/exceptions/index.spec.js @@ -0,0 +1,178 @@ +import { calculator, isAllTrue, isSomeTrue, returnBadArguments } from './index'; + +describe('ДЗ 2 - работа с исключениями и отладчиком', () => { + describe('isAllTrue', () => { + it('должна вызывать fn для всех элементов массива', () => { + const array = ['l', 's']; + const pass = []; + + isAllTrue(array, (e) => pass.push(e)); + + expect(pass).toEqual(array); + }); + + it('должна вернуть true, если fn вернула true для всех элементов массива', () => { + const array = [1, 2, 3]; + const result = isAllTrue(array, Number.isFinite); + + expect(result); + }); + + it('должна вернуть false, если fn вернула false хотя бы для одного элемента массива', () => { + const array = [1, 2, 3]; + + array.push('ls'); + const result = isAllTrue(array, Number.isFinite); + + expect(!result); + }); + + it('должна выбросить исключение, если передан пустой массив', () => { + expect(() => isAllTrue([], () => {})).toThrow('empty array'); + }); + + it('должна выбросить исключение, если передан не массив', () => { + expect(() => isAllTrue(':(', () => {})).toThrow('empty array'); + expect(() => isAllTrue({}, () => {})).toThrow('empty array'); + }); + + it('должна выбросить исключение, если fn не функция', () => { + const array = [1, 2, 3]; + + expect(() => isAllTrue(array, ':(')).toThrow('fn is not a function'); + }); + }); + + describe('isSomeTrue', () => { + it('должна вернуть true, если fn вернула true хотя бы для одного элемента массива', () => { + const array = ['l', 's', 3]; + const result = isSomeTrue(array, Number.isFinite); + + expect(result); + }); + + it('должна вернуть false, если fn не вернула true хотя бы для одного элемента массива', () => { + const array = ['l', 's']; + const result = isSomeTrue(array, Number.isFinite); + + expect(!result); + }); + + it('должна выбросить исключение, если передан пустой массив', () => { + expect(() => isSomeTrue([], () => {})).toThrow('empty array'); + }); + + it('должна выбросить исключение, если передан не массив', () => { + expect(() => isSomeTrue(':(', () => {})).toThrow('empty array'); + expect(() => isSomeTrue({}, () => {})).toThrow('empty array'); + }); + + it('должна выбросить исключение, если fn не функция', () => { + const array = [1, 2, 3]; + + expect(() => isSomeTrue(array, ':(')).toThrow('fn is not a function'); + }); + }); + + describe('returnBadArguments', () => { + it('должна вызывать fn для всех элементов массива', () => { + const array = [1, 2, 3]; + const pass = []; + + returnBadArguments((e) => pass.push(e), ...array); + + expect(pass).toEqual(array); + }); + + it('должна вернуть массив с аргументами, для которых fn выбрасила исключение', () => { + const evenNumbers = [2, 4, 6]; + const oddNumbers = [1, 3, 5]; + const fn = (a) => { + if (a % 2 !== 0) { + throw new Error('not even'); + } + }; + const result = returnBadArguments(fn, ...evenNumbers, ...oddNumbers); + + expect(result).toEqual(oddNumbers); + }); + + it('должна вернуть массив пустой массив, если не передано дополнительных аргументов', () => { + const fn = () => ':)'; + const result = returnBadArguments(fn); + + expect(result.length).toBe(0); + }); + + it('должна выбросить исключение, если fn не функция', () => { + expect(() => returnBadArguments(':(')).toThrow('fn is not a function'); + }); + }); + + describe('calculator', () => { + it('должна возвращать объект с методами', () => { + const calc = calculator(); + + expect(Object.keys(calc)).toEqual(['sum', 'dif', 'div', 'mul']); + }); + + it('метод sum должен складывать аргументы', () => { + const initialValue = 20; + const calc = calculator(initialValue); + const args = [1, 2, 3]; + + expect(calc.sum(...args)).toBe( + args.reduce((prev, current) => prev + current, initialValue) + ); + }); + + it('метод dif должен вычитать аргументы', () => { + const initialValue = 10; + const calc = calculator(initialValue); + const args = [1, 2, 3]; + + expect(calc.dif(...args)).toBe( + args.reduce((prev, current) => prev - current, initialValue) + ); + }); + + it('метод div должен делить аргументы', () => { + const initialValue = 20; + const calc = calculator(initialValue); + const args = [1, 2]; + + expect(calc.div(...args)).toBe( + args.reduce((prev, current) => prev / current, initialValue) + ); + }); + + it('метод div должен выбрасывать исключение, если хотя бы один из аргументов равен 0', () => { + const initialValue = 20; + const calc = calculator(initialValue); + const args = [1, 2, 0]; + + expect(() => calc.div(...args)).toThrow('division by 0'); + }); + + it('метод mul должен умножать аргументы', () => { + const initialValue = 10; + const calc = calculator(initialValue); + const args = [1, 2]; + + expect(calc.mul(...args)).toBe( + args.reduce((prev, current) => prev * current, initialValue) + ); + }); + + it('функция должна выбрасывать исключение, если number не является числом', () => { + expect(() => calculator(':(')).toThrow('number is not a number'); + }); + + it('значение по умолчанию для аргумента number должно быть равно 0', () => { + const calc = calculator(); + const args = [1, 2]; + + expect(calc.sum(...args)).toBe(args.reduce((prev, current) => prev + current)); + }); + }); +});