Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 02.11.2016, 12:45
Аватар для spo
spo spo вне форума
Профессор
Отправить личное сообщение для spo Посмотреть профиль Найти все сообщения от spo
 
Регистрация: 11.05.2011
Сообщений: 213

Задачи по js
Здравствуйте, друзья.
Прошу проверить, выполненные мной задачи по js

Первые две задачи очень похожи и я попробовал написать для них решения чуть по-разному
Если оба решения правильны, то подскажите какое из них более грамотное?
Так же буду признателен за примеры оптимальных решений для всех задач

Задача #1

Условие

Написать функцию `isAllTrue`, которая принимает 2 параметра: `source` и `filterFn`, где `source` - массив, `filterFn` - фильтрующая функция
Если фильтрующая функция вернет `true` для ВСЕХ элементов массива, то и сама `isAllTrue` вернет `true`
Если фильтрующая функция вернет `false` хотя бы для одного элемента массива, то и сама `isAllTrue` вернет `false`
Выбрасывать и обрабатывать исключение, если в 'source' пустой массив

Пример

var allNumbers = [1, 2, 4, 5, 6, 7, 8],
    someNumbers = [1, 2, 'привет', 4, 5, 'мир', 6, 7, 8],
    noNumbers = ['это', 'массив', 'без', 'чисел'];

function isNumber(val) {
    return typeof val === 'number';
}

console.log(isAllTrue(allNumbers, isNumber)); //вернет true
console.log(isAllTrue(someNumbers, isNumber)); //вернет false
console.log(isAllTrue(noNumbers, isNumber)); //вернет false


Решение

let source1 = [1,2,3],
	source2 = ['text',2],
	source3 = [1,'text'],
	source4 = [1,'text',3],
	source5 = ['text1','text2'],
	source6 = [];

function isAllTrue(src, fltr) {
	if (src.length == 0) {
		throw new Error('Массив пустой');
	}
	let result = true;
	for (let i = 0; i < src.length; i++) {
		if (fltr(src[i]) != true) {
			result = false;
		}
	}
	return result;
}

function filterFn(arg) {
	return typeof arg === 'number';
}

try {
	let res = isAllTrue(source6, filterFn);
	console.log('%s %s', 'Задача №1: ', res);
} catch(e) {
	console.error('%s %s', 'Задача №1: ', e.message);
}


Задача #2

Условие

Написать функцию 'isSomeTrue', которая принимает 2 параметра - 'source' и 'filterFn', где 'source' - массив, 'filterFn' - фильтрующая функция
Если фильтрующая функция вернет 'false' для ВСЕХ элементов массива, то и сама 'isSomeTrue' вернет 'false'
Если фильтрующая функция вернет 'true' хотя бы для одного элемента массива, то и сама 'isSomeTrue' вернет 'true'
Всё должно быть реализовано с использованием чистого js (не используя сторонние библиотеки)
Так же, нельзя использовать функции для работы с массивами

Решение

let source1 = [1,2,3],
	source2 = ['text',2],
	source3 = [1,'text'],
	source4 = [1,'text',3],
	source5 = ['text1','text2'];

function isAllTrue(src, fltr) {
	let result;
	for (let i = 0; i < src.length; i++) {
		if (fltr(src[i]) == true) {
			result = true;
			return result;
		} else {
			result = false;
		}
	}
	return result;
}

function filterFn(arg) {
	return typeof arg === 'number';
}

let res = isAllTrue(source5, filterFn);
console.log('%s %s', 'Задача №2: ', res);


Задача №3

Условие

Написать функцию 'calculator' (в виде модуля), которая имеет один параметр - 'firstNumber', где 'firstNumber' - это число, с которым будут производиться действия
Функция 'calculator' должна возвращать объект, у которого должно быть несколько функций
  • 'sum' - складывает 'firstNumber' с переданными аргументами
  • 'dif' - вычитает из 'firstNumber' переданные аргументы
  • 'div' - делит 'firstNumber' на первый переданный аргумент. Результат этой операции делится на второй переданный аргумент (если он есть) и так далее
  • 'mul' - умножает 'firstNumber' на первый переданный аргумент. Результат этой операции умножается на второй переданный аргумент (если он есть) и так далее
Каждая из этих функций принимает неограниченное количество аргументов и производит какие-то арифметические операции с этими аргументами и тем числом, которое было передано в 'calculator' и возвращает результат
Предусмотреть исключительные ситуации, для функции 'div', когда делитель равен нулю

Пример

let myCalculator = calculator(100);

console.log(myCalculator.sum(1, 2, 3)); //вернет 106
console.log(myCalculator.dif(10, 20)); //вернет 70
console.log(myCalculator.div(2, 2)); //вернет 25
console.log(myCalculator.mul(2, 2)); //вернет 400


Решение

Файл calculator.js

let calc = function calculator(firstNumber) {
	let result = firstNumber;
	let obj = {
		sum: function() {
			for(let i = 0; i < arguments.length; i++) {
				result += arguments[i];
			}
			return result;
		},
		dif: function() {
			for(let i = 0; i < arguments.length; i++) {
				console.log(result);
				result -= arguments[i];
			}
			return result;
		},
		div: function() {
			for(let i = 0; i < arguments.length; i++) {
				if (arguments[i] == 0) {
					throw new Error('Делитель равен нулю');
				} else {
					result /= arguments[i];
				}
			}
			return result;
		},
		mul: function() {
			for(let i = 0; i < arguments.length; i++) {
				result *= arguments[i];
			}
			return result;
		},
	}
	return obj;
}

module.exports = calc;


Файл script.js

let calcFn = require('./calculator.js');

let myCalc = calcFn(8);
console.log('%s %s', 'Задача №3: ', myCalc.sum(3, 2, 0));
console.log('%s %s', 'Задача №3: ', myCalc.dif(3, 2, 0));
try {
	console.log('%s %s', 'Задача №3: ', myCalc.div(3, 2, 0));
} catch(e) {
	console.error('%s %s', 'Задача №3: ', e.message);
}
console.log('%s %s', 'Задача №3: ', myCalc.mul(3, 2, 0));
Ответить с цитированием
  #2 (permalink)  
Старый 02.11.2016, 18:01
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,490

Ну на вскидку всё верно, разве что в первой задаче после result = false, следует сделать break из цикла, ибо одного false достаточно. Во второй же задаче, аналогично, else лишний: нет никакого смысла каждую итерацию переопределять result как false, т.к. первый же true приведёт к завершению функции, имеет смысл присвоить result = false в самом начале по аналогии с первой функциией.
Ставить в циклах break, а return делать в конце, или делать return сразу в цикле - вопрос исключительно стиля кода, т.е. делайте так, как вам преподают.
То же касательно if(foo == true) vs if(foo) и if(bar != true), if(bar == false) vs if(!bar), первое нагляднее и считается более правильным, но второе проще и встретить можно чаще.

По последней функции: поскольку вы используете let, то, надо полагать, подразумевается самый современный javascript, тогда можно было бы сделать всё по-модному, например:
dif: function() {
            for(let i = 0; i < arguments.length; i++) {
                console.log(result);
                result -= arguments[i];
            }
            return result;
        },
->
dif: (...args) => args.reduce( (a, b) => a - b, result ),
Но это если только вам показывали такую "магию". Сам по себе ваш вариант ничуть не хуже, и скорее всего даже производительнее.)

Единственный момент, в последней функции у вас переменная result для всех методов едина, а значит все вычисления для конкретного myCalculator сохраняются, что было бы логично, но судя по примеру каждый раз вычисления должны начинаться с изначального значения.
__________________
29375, 35

Последний раз редактировалось Aetae, 02.11.2016 в 18:28.
Ответить с цитированием
  #3 (permalink)  
Старый 02.11.2016, 18:25
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,490

Ну и разумным шагом было бы превратить Calculator в конструктор:
function Calculator(firstNumber) {
  if(!(this instanceof Calculator)) return new Calculator(firstNumber);
  this.firstNumber = firstNumber;
}
Calculator.prototype = {
  sum: function() {
    let result = this.firstNumber;
    for(let i = 0; i < arguments.length; i++) {
      result += arguments[i];
    }
    return result;
  },
  dif: function() {
    let result = this.firstNumber;
    for(let i = 0; i < arguments.length; i++) {
      result -= arguments[i];
    }
    return result;
  },
  div: function() {

    let result = this.firstNumber;
    for(let i = 0; i < arguments.length; i++) {
      if (arguments[i] == 0) {
        throw new Error('Делитель равен нулю');
      } else {
        result /= arguments[i];
      }
    }
    return result;
  },
  mul: function() {
    let result = this.firstNumber;
    for(let i = 0; i < arguments.length; i++) {
      result *= arguments[i];
    }
    return result;
  },
}

module.exports = Calculator;
Разница с вашим вариантом(кроме исправления result) в том, что для каждого новосозданного объекта будут использованы одни и те же функции, без копирования, тогда как у вас каждый раз они создаются заново.

Но, опять же, использовать это имеет смысл, если вы проходили что такое прототипы.)

P.S. На счёт оптимальных первых двух задач - вопрос тонкий, ибо в современном js существуют нативные some и every.
__________________
29375, 35

Последний раз редактировалось Aetae, 02.11.2016 в 18:39.
Ответить с цитированием
  #4 (permalink)  
Старый 02.11.2016, 22:55
Профессор
Отправить личное сообщение для DivMan Посмотреть профиль Найти все сообщения от DivMan
 
Регистрация: 08.03.2016
Сообщений: 429

А ты попробуй через рекурсию
Ответить с цитированием
  #5 (permalink)  
Старый 02.11.2016, 23:00
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,490

Рекурсия тут не пришей к п... не нужна, в общем, совсем.
__________________
29375, 35
Ответить с цитированием
  #6 (permalink)  
Старый 09.11.2016, 16:47
Аватар для spo
spo spo вне форума
Профессор
Отправить личное сообщение для spo Посмотреть профиль Найти все сообщения от spo
 
Регистрация: 11.05.2011
Сообщений: 213

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

Задача #4

Условие

Напишите модуль, который экспортирует функцию с именем `consoleRec`
Функция должна рекурсивно выводить элементы массива на экран
Запрещено использовать циклы и методы для работы с массивами
Функция должна принимать два аргумента: массив и что-то еще на ваше усмотрение

Пример

consoleRec(['я', 'умею', 'писать', 'рекурсивные', 'функции']);


Должна вывести на экран:

я
умею
писать
рекурсивные
функции

Решение

Файл script.js

let recurtion = require('./recurtion.js'),
	array = ['я', 'умею', 'писать', 'рекурсивные', 'функции'],
	myName = 'spo';
	
recurtion(array, myName);


Файл recurtion.js

let i = 0;

module.exports = function consoleRec(arr, name) {
	if(i < arr.length) {
		if(i == 0) {
			console.log(arr[i] + ' - ' + name);
		} else {
			console.log(arr[i]);
		}
		i++;
		consoleRec(arr, name);
	}
}


Вопрос

Про module.exports пока знаю мало и не понимаю почему, экспортируя только функцию, я имею доступ и к переменной i?

Последний раз редактировалось spo, 09.11.2016 в 16:50.
Ответить с цитированием
  #7 (permalink)  
Старый 09.11.2016, 21:05
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,490

Нет, оно конечно сработает. Но только один раз, ибо при следующем вызове i будет равно длине массива из предыдущего вызова, а не нулю. Т.к. функция импортируется единожды, единожды импортируется и "верхняя" i, которую функция свободно изменяет.
Решений данной задачи множество, и самый простой вариант - передавать i дополнительным параметром.

По поводу это самой i. Важнейшая для понимания javascript как такового информация.
__________________
29375, 35
Ответить с цитированием
  #8 (permalink)  
Старый 09.11.2016, 23:29
Аватар для spo
spo spo вне форума
Профессор
Отправить личное сообщение для spo Посмотреть профиль Найти все сообщения от spo
 
Регистрация: 11.05.2011
Сообщений: 213

Возможно именно на это намекает условие, когда говорит про второй параметр. А я не так понял и передал произвольный ) Спасибо.
Ответить с цитированием
  #9 (permalink)  
Старый 07.02.2018, 16:25
Новичок на форуме
Отправить личное сообщение для slava.jax Посмотреть профиль Найти все сообщения от slava.jax
 
Регистрация: 07.02.2018
Сообщений: 1

Я думаю, что второй параметр используется именно для этого:

let consoleRec = (source, iter) => {
    if (source[iter] !== undefined) {
        console.log(source[iter++]);
        consoleRec(source, iter);
    }
}

module.exports = {
    'consoleRec': consoleRec
};


А использовать можно так:

let tools = require('./tools.js');
tools.consoleRec(['я', 'умею', 'писать', 'рекурсивные', 'функции'], 0);

Последний раз редактировалось slava.jax, 07.02.2018 в 16:27. Причина: Дополнение
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
js стиль render для react.js vflash Ваши сайты и скрипты 5 01.04.2016 22:57
Вакансия JavaScript разработчик / JS / Frontend developer (Санкт-Петербург) Сергей Грачёв Работа 0 21.09.2015 12:31
JS <-> Server Js. Severtain Общие вопросы Javascript 1 05.11.2011 15:36
JS Coaching для стартапа OlgaAyva Работа 12 27.09.2011 22:18
Картинка обрабатывается js 4yBaK Общие вопросы Javascript 10 11.09.2011 09:28