Fizzbuzz — це популярне завдання з програмування.
Ось умова:
Програма повинна вивести числа від 1 до 100 включно, але:
Якщо число ділиться на 3, заміняємо його на ‘Fizz’
Якщо число ділиться на 5, заміняємо його на ‘Buzz’
Якщо число ділиться на обидва, заміняємо його на ‘FizzBuzz’
Ми використовуємо це просте завдання, щоб дослідити різні способи вираження одного і того ж рішення за допомогою JS.
Перша реалізація
for(let num = 1; num <= 100; num++) {
if (num % 3 === 0 && num % 5 === 0) // 1.
console.log('FizzBuzz')
else if (num % 3 === 0) // 2.
console.log('Fizz')
else if (num % 5 === 0) // 2.
console.log('Buzz')
else
console.log(num) // 3.
}
Перша частина, яку я хочу дослідити, це як усунути дублювання, яке існує. Наразі операція модуля %
(яка отримує залишок від ділення на 3 і на 5) повторюється двічі:
(1.
) Коли обидві умови виконуються
(2.
) Коли кожна умова виконується окремо
(3.
) Також повторюється в усіх гілках нашої програми console.log
.
Рефакторинг
for(let num = 1; num <= 100; num++) {
let replacement = '' // 1.
if (num % 3 === 0)
replacement += 'Fizz'
if (num % 5 === 0)
replacement += 'Buzz'
console.log(replacement ? replacement : num) // 2.
}
(1.
) Використовуємо порожній рядок для накопичення можливого заміщення кожного числа. Усуваємо повторення операцій %
та console.log
за допомогою введення змінної, яка змінюється з часом.
(2.
) Використовуємо те, що в JS порожній рядок оцінюється як false
, щоб застосувати тернарний оператор: якщо є щось, що замінює число, виводимо це. Якщо ж ні — виводимо число.
Ми усунули дублювання, і, на мою думку, код став значно яснішим і лаконічнішим. Однак можна ще більше спростити.
Мінімалістичний підхід
for(let num = 1; num <= 100; num++) {
const replacement =
(num % 3? '': 'Fizz') +
(num % 5? '': 'Buzz') // 1.
console.log(replacement || num) // 2.
}
(1.
) Якщо жодне правило не застосовується, додаються два порожні рядки, що дають результат у вигляді порожнього рядка. Якщо одне або кілька правил застосовуються, вони додаються.
(2.
) Логічний оператор OR ||
повертає перший результат, який оцінюється як true
. У цьому випадку він поверне replacement
, якщо цей рядок містить текст, інакше поверне число.
Це рішення вимагає, щоб людина, яка читає наш код, була знайома з приведенням типів у JavaScript.
З іншого боку, усуваючи пробіли та застосовуючи хитрість у оголошенні циклу, ми можемо виразити нашу програму в одному рядку.
Однорядковий варіант
for(i=0;++i<100;)console.log((i%3?'':'Fizz')+(i%5?'':'Buzz')||i)
Ми тільки що вирішили задачу FizzBuzz за 64 байти JS 🙂
Оголошення циклів поділено на три частини, розділені крапками з комою: for( ; ; )
У цьому випадку в другій частині оголошення ми збільшуємо i
, одночасно перевіряючи, чи знаходиться вона в межах ліміту, залишаючи останній блок for
порожнім: for(i=0; ++i < 100; )
Це рішення може бути хорошим для вправи з code golfing і працює так само, як і попередні, але воно надзвичайно криптографічне.
У частині 2 ми продовжимо досліджувати цю програму, шукаючи способи покращити гнучкість та читабельність нашого коду.
Перекладено з: Explorando JS con FizzBuzz (1/2)