A ticking clock using functional programming (JS)

A ticking clock using functional programming (JS)

in functional way

Imperative solution in non-functional way:

// Log clock time every second
setInterval(logClockTime, 1000);

function logClockTime() {
  // Get time string
  let time = getClockTime();

  // Clear the console and log the time
  console.clear();
  console.log(time);
}

function getClockTime() {
  // Get the current time
  let date = new Date();

  // Serialize clock time
  let time = {
    hours: date.getHours(),
    minutes: date.getMinutes(),
    seconds: date.getSeconds(),
    apm: 'AM'
  };

  // Convert to civilian time
  if (time.hours >= 12) time.apm = 'PM';
  if (time.hours > 12) time.hours -= 12;

  // Prepend a leading 0 on the hours/minutes/seconds to make double digits
  if (time.hours < 10) time.hours = `0${time.hours}`;
  if (time.minutes < 10) time.minutes = `0${time.minutes}`;
  if (time.seconds < 10) time.seconds = `0${time.seconds}`;

  // Format the clock time as a string 'hh:mm:ss tt'
  return `${time.hours}:${time.minutes}:${time.seconds} ${time.apm}`;
}

Now, let’s break the application logic up into smaller function parts.

In functional programs, we should use functions over values wherever possible:

const oneSecond = () => 1000;
const getCurrentTime = () => new Date();
const clear = () => console.clear();
const log = (message) => console.log(message);

// serialize date to clock time
const serializeClockTime = (date) => ({
  hours: date.getHours(),
  minutes: date.getMinutes(),
  seconds: date.getSeconds()
})

// turn clock time to civilian time
const civilianHours = (clockTime) => ({
  ...clockTime,
  hours: clockTime.hours > 12 ? clockTime.hours - 12 : clockTime.hours
})

// append AM/PM
const appendAPM = (clockTime) => ({
  ...clockTime,
  apm: clockTime.hours >= 12 ? 'PM': 'AM'
})

// here 'fn' will be console.log
const display = fn => time => fn(time);

// format clock with template string 'hh:mm:ss tt'
const formatClock = format => time => {
  return format.replace('hh', time.hours)
    .replace('mm', time.minutes)
    .replace('ss', time.seconds)
    .replace('tt', time.apm)
}

// prepend leading zero
const prependZero = key => clockTime => ({
  ...clockTime,
  [key]: clockTime[key] < 10 ? `0${clockTime[key]}` : clockTime[key]
})

// compose functional parts
const compose = (...fns) => arg => fns.reduce((composed, f) => f(composed), arg);

const convertToCivilianTime = clockTime => {
  return compose(
    appendAPM,
    civilianHours
  )(clockTime)
}

const doubleDigits = civilianTime =>
  compose(
    prependZero('hours'),
    prependZero('minutes'),
    prependZero('seconds')
  )(civilianTime)

const startTicking = () => {
  setInterval(
    compose(
      clear,
      getCurrentTime,
      serializeClockTime,
      convertToCivilianTime,
      doubleDigits,
      formatClock('hh:mm:ss tt'),
      display(log)
    ), oneSecond()
  )
}

startTicking();
Ads by Google

林宏

Frank Lin

Hey, there! This is Frank Lin (@flinhong), one of the 1.41 billion 🇨🇳. This 'inDev. Journal' site holds the exploration of my quirky thoughts and random adventures through life. Hope you enjoy reading and perusing my posts.

YOU MAY ALSO LIKE

Using Liquid in Jekyll - Live with Demos

Web Notes

2016.08.20

Using Liquid in Jekyll - Live with Demos

Liquid is a simple template language that Jekyll uses to process pages for your site. With Liquid you can output complex contents without additional plugins.

HTML 相对路径和绝对路径区别分析

Web Notes

2015.09.26

HTML 相对路径和绝对路径区别分析

HTML 初学者会经常遇到这样一个问题,如何正确引用一个文件。比如,怎样在一个 HTML 网页中引用另外一个 HTML 网页作为超链接(hyperlink),怎样在一个网页中插入一张图片。如果你在引用文件时(如加入超链接,或者插入图片等),使用了错误的文件路径,就会导致引用失效(无法浏览链接文件,或无法显示插入的图片等)。

Hands on IBM Cloud Functions with CLI

Tools

2020.10.20

Hands on IBM Cloud Functions with CLI

IBM Cloud CLI allows complete management of the Cloud Functions system. You can use the Cloud Functions CLI plugin-in to manage your code snippets in actions, create triggers, and rules to enable your actions to respond to events, and bundle actions into packages.