diff --git a/src/core.js b/src/core.js index 9235599..679f3b9 100644 --- a/src/core.js +++ b/src/core.js @@ -1,80 +1,179 @@ -//Напишите функцию, которая проверяет, является ли число целым используя побитовые операторы -function isInteger(n) {} - -//Напишите функцию, которая возвращает массив четных чисел от 2 до 20 включительно -function even() {} - -//Напишите функцию, считающую сумму чисел до заданного используя цикл -function sumTo(n) {} - -//Напишите функцию, считающую сумму чисел до заданного используя рекурсию -function recSumTo(n) {} - -//Напишите функцию, считающую факториал заданного числа -function factorial(n) {} - -//Напишите функцию, которая определяет, является ли число двойкой, возведенной в степень -function isBinary(n) {} - -//Напишите функцию, которая находит N-е число Фибоначчи -function fibonacci(n) {} - -/** Напишите функцию, которая принимает начальное значение и функцию операции - * и возвращает функцию - выполняющую эту операцию. - * Если функция операции (operatorFn) не задана - по умолчанию всегда - * возвращается начальное значение (initialValue) - * @param initialValue - * @param operatorFn - (storedValue, newValue) => {operation} - * @example - * const sumFn = getOperationFn(10, (a,b) => a + b); - * console.log(sumFn(5)) - 15 - * console.log(sumFn(3)) - 18 - */ -function getOperationFn(initialValue, operatorFn) {} - -/** - * Напишите функцию создания генератора арифметической последовательности. - * При ее вызове, она возвращает новую функцию генератор - generator(). - * Каждый вызов функции генератора возвращает следующий элемент последовательности. - * Если начальное значение не передано, то оно равно 0. - * Если шаг не указан, то по дефолту он равен 1. - * Генераторов можно создать сколько угодно - они все независимые. - * - * @param {number} start - число с которого начинается последовательность - * @param {number} step - число шаг последовательности - * @example - * const generator = sequence(5, 2); - * console.log(generator()); // 5 - * console.log(generator()); // 7 - * console.log(generator()); // 9 - */ -function sequence(start, step) {} - -/** - * Напишите функцию deepEqual, которая принимает два значения - * и возвращает true только в том случае, если они имеют одинаковое значение - * или являются объектами с одинаковыми свойствами, - * значения которых также равны при сравнении с рекурсивным вызовом deepEqual. - * Учитывать специфичные объекты(такие как Date, RegExp итп) не обязательно - * - * @param {object} firstObject - первый объект - * @param {object} secondObject - второй объект - * @returns {boolean} - true если объекты равны(по содержанию) иначе false - * @example - * deepEqual({arr: [22, 33], text: 'text'}, {arr: [22, 33], text: 'text'}) // true - * deepEqual({arr: [22, 33], text: 'text'}, {arr: [22, 3], text: 'text2'}) // false - */ -function deepEqual(firstObject, secondObject) {} - -module.exports = { - isInteger, - even, - sumTo, - recSumTo, - factorial, - isBinary, - fibonacci, - getOperationFn, - sequence, - deepEqual, -}; +//Напишите функцию, которая проверяет, является ли число целым используя побитовые операторы +function isInteger(n) { + return ~~n === n +} + +//Напишите функцию, которая возвращает массив четных чисел от 2 до 20 включительно +function even() { + let evenNum = 2; + let result = []; + + while (evenNum <= 20) { + result.push(evenNum); + evenNum += 2; + } + + return result +} + +//Напишите функцию, считающую сумму чисел до заданного используя цикл +function sumTo(n) { + let result = 0; + + for (let i = 1; i <= n; i++) { + result += i; + } + + return result +} + +//Напишите функцию, считающую сумму чисел до заданного используя рекурсию +function recSumTo(n) { + let num = 0; + let result = 0; + + while (num !== n) { + num++; + result += num; + } + + return result; +} + +//Напишите функцию, считающую факториал заданного числа +function factorial(n) { + let result = 1; + + for (let i = 1; i <= n; i++) { + result *= i; + } + + return result +} + +//Напишите функцию, которая определяет, является ли число двойкой, возведенной в степень +function isBinary(n) { + return (n.toString(2).replace(/0/g, '') === '1'); +} + +//Напишите функцию, которая находит N-е число Фибоначчи +function fibonacci(n) { + let prevNum = 0; + let curNum = 1; + + for (let i = 1; i < n; i++) { + const tempNum = curNum; + curNum += prevNum; + prevNum = tempNum; + } + + return curNum; +} + +/** Напишите функцию, которая принимает начальное значение и функцию операции + * и возвращает функцию - выполняющую эту операцию. + * Если функция операции (operatorFn) не задана - по умолчанию всегда + * возвращается начальное значение (initialValue) + * @param initialValue + * @param operatorFn - (storedValue, newValue) => {operation} + * @example + * const sumFn = getOperationFn(10, (a,b) => a + b); + * console.log(sumFn(5)) - 15 + * console.log(sumFn(3)) - 18 + */ +function getOperationFn(initialValue, operatorFn) { + if (!operatorFn) { + return () => initialValue; + } + + let firstValue = initialValue; + + return (newValue) => { + + const result = operatorFn(firstValue, newValue); + firstValue = operatorFn(firstValue, newValue); + + return result; + } +} + +/** + * Напишите функцию создания генератора арифметической последовательности. + * При ее вызове, она возвращает новую функцию генератор - generator(). + * Каждый вызов функции генератора возвращает следующий элемент последовательности. + * Если начальное значение не передано, то оно равно 0. + * Если шаг не указан, то по дефолту он равен 1. + * Генераторов можно создать сколько угодно - они все независимые. + * + * @param {number} start - число с которого начинается последовательность + * @param {number} step - число шаг последовательности + * @example + * const generator = sequence(5, 2); + * console.log(generator()); // 5 + * console.log(generator()); // 7 + * console.log(generator()); // 9 + */ +function sequence(start = 0, step = 1) { + let genNum = start; + + return () => { + const result = genNum; + genNum += step; + return result + } +} + +/** + * Напишите функцию deepEqual, которая принимает два значения + * и возвращает true только в том случае, если они имеют одинаковое значение + * или являются объектами с одинаковыми свойствами, + * значения которых также равны при сравнении с рекурсивным вызовом deepEqual. + * Учитывать специфичные объекты(такие как Date, RegExp итп) не обязательно + * + * @param {object} firstObject - первый объект + * @param {object} secondObject - второй объект + * @returns {boolean} - true если объекты равны(по содержанию) иначе false + * @example + * deepEqual({arr: [22, 33], text: 'text'}, {arr: [22, 33], text: 'text'}) // true + * deepEqual({arr: [22, 33], text: 'text'}, {arr: [22, 3], text: 'text2'}) // false + */ +function deepEqual(firstObject, secondObject) { + if (firstObject === secondObject || (String(firstObject) === 'NaN' && String(secondObject) === 'NaN')) { + return true + } + + if (typeof(firstObject) !== 'object' || firstObject === null || typeof(secondObject) !== 'object' || secondObject === null) { + return false; + } + + if (Object.keys(firstObject).length !== Object.keys(secondObject).length) { + return false; + } + + for (let key in firstObject) { + if (!secondObject.hasOwnProperty(key)) { + return false; + } + + if (typeof(firstObject[key] === 'object')) { + if (!deepEqual(firstObject[key], secondObject[key])) { + return false; + } + } + } + + return true +} + +module.exports = { + isInteger, + even, + sumTo, + recSumTo, + factorial, + isBinary, + fibonacci, + getOperationFn, + sequence, + deepEqual, +}; \ No newline at end of file diff --git a/src/core.spec.js b/src/core.spec.js index 91286b6..4f47eef 100644 --- a/src/core.spec.js +++ b/src/core.spec.js @@ -1,186 +1,186 @@ -const assert = require('assert'), - core = require('./core'); - -describe('Задания core js', () => { - describe('#isInteger', () => { - it('Возвращает true на целое число', () => { - assert.equal(core.isInteger(3), true); - }); - - it('Возвращает false на нецелое число', () => { - assert.equal(core.isInteger(1.2), false); - }); - }); - - describe('#even', () => { - it('Возвращает корректный массив', () => { - assert.deepStrictEqual( - core.even(), - [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] - ); - }); - }); - - describe('#sumTo', () => { - it('Возвращает сумму чисел до n', () => { - assert.equal(core.sumTo(4), 10, 'С маленьким числом'); - assert.equal(core.sumTo(100), 5050, 'С большим числом'); - }); - }); - - describe('#recSumTo', () => { - it('Возвращает сумму чисел до n', () => { - assert.equal(core.recSumTo(4), 10, 'С маленьким числом'); - assert.equal(core.recSumTo(100), 5050, 'С большим числом'); - }); - }); - - describe('#factorial', () => { - it('Возвращает факториал n', () => { - assert.equal(core.factorial(5), 120); - assert.equal(core.factorial(4), 24); - }); - }); - - describe('#isBinary', () => { - it('Возвращает true при передаче степени двойки', () => { - assert.equal(core.isBinary(1), true); - assert.equal(core.isBinary(2), true); - assert.equal(core.isBinary(2048), true); - }); - - it('Возвращает false при передаче не степени двойки', () => { - assert.equal(core.isBinary(0), false); - assert.equal(core.isBinary(12), false); - assert.equal(core.isBinary(1023), false); - }); - }); - - describe('#fibonacci', () => { - it('Возвращает n-ое число Фибоначчи корректно', () => { - assert.equal(core.fibonacci(1), 1); - assert.equal(core.fibonacci(2), 1); - assert.equal(core.fibonacci(7), 13); - assert.equal(core.fibonacci(10), 55); - }); - }); - - describe('#getOperationFn', () => { - it('Возвращает функцию', () => { - const sumFn = core.getOperationFn(-1, (a, b) => a + b); - assert.ok(typeof sumFn === 'function'); - }); - - it('Сохраняет внутреннее значение и применяет операцию', () => { - const multFn = core.getOperationFn(-1, (a, b) => a * b); - assert.strictEqual(multFn(-1), 1); - assert.strictEqual(multFn(4), 4); - assert.strictEqual(multFn(2), 8); - }); - - it('По умолчанию всегда возвращает начальное значение, если нет operatorFn', () => { - const staticFn = core.getOperationFn(-1); - assert.strictEqual(staticFn(-1), -1); - assert.strictEqual(staticFn(7), -1); - assert.strictEqual(staticFn(0), -1); - }); - }); - - describe('#sequence', () => { - it('Возвращает функцию с шагом 1 и началом 0, если не переданы значения', () => { - const generator = core.sequence(); - assert.equal(generator(), 0); - assert.equal(generator(), 1); - assert.equal(generator(), 2); - }); - - it('Функция-генератор корректно генерирует значения начиная со start с шагом step', () => { - const generator1 = core.sequence(10, 3); - const generator2 = core.sequence(8, 2); - assert.equal(generator1(), 10); - assert.equal(generator1(), 13); - assert.equal(generator2(), 8); - assert.equal(generator1(), 16); - assert.equal(generator2(), 10); - }); - }); - - describe('#deepEqual', () => { - const dummyFunction = () => {}; - - it('Возвращает true если объекты равны', () => { - assert.equal( - core.deepEqual( - {text: 'some text', count: 3, arr: [11, 22]}, - {text: 'some text', count: 3, arr: [11, 22]} - ), - true - ); - assert.equal( - core.deepEqual( - {obj: {count: 12}, value: null, flag: true}, - {obj: {count: 12}, value: null, flag: true} - ), - true - ); - assert.equal( - core.deepEqual( - {obj: {arr: ['a', 'b']}, value: undefined}, - {obj: {arr: ['a', 'b']}, value: undefined} - ), - true - ); - assert.equal( - core.deepEqual({func: dummyFunction}, {func: dummyFunction}), - true - ); - assert.equal( - core.deepEqual({a: 'a', b: 'b'}, {b: 'b', a: 'a'}), - true - ); - assert.equal(core.deepEqual(NaN, NaN), true); - }); - - it('Возвращает false если объекты не равны', () => { - assert.equal( - core.deepEqual( - {text: 'some text', count: 3, arr: [11, 22]}, - {text: 'some text1', count: 4, arr: [11, 22]} - ), - false - ); - assert.equal( - core.deepEqual( - {obj: {count: 12}, value: null, flag: true}, - {obj: {count: 22}, value: null, flag: false} - ), - false - ); - assert.equal( - core.deepEqual( - {obj: {arr: ['a', 'b']}, value: undefined}, - {obj: {arr: ['a', 'b']}, value: null} - ), - false - ); - assert.equal( - core.deepEqual( - {obj: {arr: [1, 2, 3]}, value: 'null', n: 0}, - {obj: {arr: [1, 2]}, value: 'null', n: 0} - ), - false - ); - assert.equal( - core.deepEqual({obj: {arr: [1, 0]}}, {obj: {arr: [1, null]}}), - false - ); - assert.strictEqual(core.deepEqual(0, 1), false); - assert.strictEqual(core.deepEqual(null, 0), false); - assert.strictEqual(core.deepEqual(null, undefined), false); - assert.equal( - core.deepEqual({func: dummyFunction}, {func: () => {}}), - false - ); - }); - }); -}); +const assert = require('assert'), + core = require('./core'); + +describe('Задания core js', () => { + describe('#isInteger', () => { + it('Возвращает true на целое число', () => { + assert.equal(core.isInteger(3), true); + }); + + it('Возвращает false на нецелое число', () => { + assert.equal(core.isInteger(1.2), false); + }); + }); + + describe('#even', () => { + it('Возвращает корректный массив', () => { + assert.deepStrictEqual( + core.even(), + [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] + ); + }); + }); + + describe('#sumTo', () => { + it('Возвращает сумму чисел до n', () => { + assert.equal(core.sumTo(4), 10, 'С маленьким числом'); + assert.equal(core.sumTo(100), 5050, 'С большим числом'); + }); + }); + + describe('#recSumTo', () => { + it('Возвращает сумму чисел до n', () => { + assert.equal(core.recSumTo(4), 10, 'С маленьким числом'); + assert.equal(core.recSumTo(100), 5050, 'С большим числом'); + }); + }); + + describe('#factorial', () => { + it('Возвращает факториал n', () => { + assert.equal(core.factorial(5), 120); + assert.equal(core.factorial(4), 24); + }); + }); + + describe('#isBinary', () => { + it('Возвращает true при передаче степени двойки', () => { + assert.equal(core.isBinary(1), true); + assert.equal(core.isBinary(2), true); + assert.equal(core.isBinary(2048), true); + }); + + it('Возвращает false при передаче не степени двойки', () => { + assert.equal(core.isBinary(0), false); + assert.equal(core.isBinary(12), false); + assert.equal(core.isBinary(1023), false); + }); + }); + + describe('#fibonacci', () => { + it('Возвращает n-ое число Фибоначчи корректно', () => { + assert.equal(core.fibonacci(1), 1); + assert.equal(core.fibonacci(2), 1); + assert.equal(core.fibonacci(7), 13); + assert.equal(core.fibonacci(10), 55); + }); + }); + + describe('#getOperationFn', () => { + it('Возвращает функцию', () => { + const sumFn = core.getOperationFn(-1, (a, b) => a + b); + assert.ok(typeof sumFn === 'function'); + }); + + it('Сохраняет внутреннее значение и применяет операцию', () => { + const multFn = core.getOperationFn(-1, (a, b) => a * b); + assert.strictEqual(multFn(-1), 1); + assert.strictEqual(multFn(4), 4); + assert.strictEqual(multFn(2), 8); + }); + + it('По умолчанию всегда возвращает начальное значение, если нет operatorFn', () => { + const staticFn = core.getOperationFn(-1); + assert.strictEqual(staticFn(-1), -1); + assert.strictEqual(staticFn(7), -1); + assert.strictEqual(staticFn(0), -1); + }); + }); + + describe('#sequence', () => { + it('Возвращает функцию с шагом 1 и началом 0, если не переданы значения', () => { + const generator = core.sequence(); + assert.equal(generator(), 0); + assert.equal(generator(), 1); + assert.equal(generator(), 2); + }); + + it('Функция-генератор корректно генерирует значения начиная со start с шагом step', () => { + const generator1 = core.sequence(10, 3); + const generator2 = core.sequence(8, 2); + assert.equal(generator1(), 10); + assert.equal(generator1(), 13); + assert.equal(generator2(), 8); + assert.equal(generator1(), 16); + assert.equal(generator2(), 10); + }); + }); + + describe('#deepEqual', () => { + const dummyFunction = () => {}; + + it('Возвращает true если объекты равны', () => { + assert.equal( + core.deepEqual( + {text: 'some text', count: 3, arr: [11, 22]}, + {text: 'some text', count: 3, arr: [11, 22]} + ), + true + ); + assert.equal( + core.deepEqual( + {obj: {count: 12}, value: null, flag: true}, + {obj: {count: 12}, value: null, flag: true} + ), + true + ); + assert.equal( + core.deepEqual( + {obj: {arr: ['a', 'b']}, value: undefined}, + {obj: {arr: ['a', 'b']}, value: undefined} + ), + true + ); + assert.equal( + core.deepEqual({func: dummyFunction}, {func: dummyFunction}), + true + ); + assert.equal( + core.deepEqual({a: 'a', b: 'b'}, {b: 'b', a: 'a'}), + true + ); + assert.equal(core.deepEqual(NaN, NaN), true); + }); + + it('Возвращает false если объекты не равны', () => { + assert.equal( + core.deepEqual( + {text: 'some text', count: 3, arr: [11, 22]}, + {text: 'some text1', count: 4, arr: [11, 22]} + ), + false + ); + assert.equal( + core.deepEqual( + {obj: {count: 12}, value: null, flag: true}, + {obj: {count: 22}, value: null, flag: false} + ), + false + ); + assert.equal( + core.deepEqual( + {obj: {arr: ['a', 'b']}, value: undefined}, + {obj: {arr: ['a', 'b']}, value: null} + ), + false + ); + assert.equal( + core.deepEqual( + {obj: {arr: [1, 2, 3]}, value: 'null', n: 0}, + {obj: {arr: [1, 2]}, value: 'null', n: 0} + ), + false + ); + assert.equal( + core.deepEqual({obj: {arr: [1, 0]}}, {obj: {arr: [1, null]}}), + false + ); + assert.strictEqual(core.deepEqual(0, 1), false); + assert.strictEqual(core.deepEqual(null, 0), false); + assert.strictEqual(core.deepEqual(null, undefined), false); + assert.equal( + core.deepEqual({func: dummyFunction}, {func: () => {}}), + false + ); + }); + }); +});