Articles

Year End Review — 2020

Hello! I want to begin the year with a year-end review again. I like doing these because it gives me a solid sense of where I am today versus where I was last year.

Giving away 10 copies of Learn JavaScript

I want to start 2021 on a good note by giving away 10 copies of my JavaScript course, Learn JavaScript. This course will help you become great at JavaScript within a short span of time. The usual price for this course is $495, so I’m gonna give away $4950 worth of value.

Rik Schennink is also joining me and giving away 5 lifetime Hobby license for his amazing Image Editor plugin, Doka. Each hobby plan is priced at $149, each year, so Rik is giving away a ton too!

Case Conversion in JavaScript

I got fed-up searching Google for case conversion utilities. The useful ones I found (Voca and change-case) both require an environment that allows me to use npm.

But I was using Vanilla JavaScript. I did not want to include any toolchains in this project, and I’m reluctant to send an asynchronous request to download a module just for case-conversion.

So I decided to write a set of conversion utilities myself.

It’s simpler than I thought.

The Common Cases

I usually use these cases when writing HTML, CSS, and JavaScript:

  • camelCase
  • kebab-case
  • Sentence case
  • Title Case

I don’t use these two cases, but I know they exist.

  • snake_case
  • PascalCase

So far, I’ve relied on simple functions that convert from one case to another. But I was fed-up with writing things like camelToTitle or camelToKebab. It’s much nicer to have a function that converts all cases to the one I need.

Converting any case to kebab-case

I started converting stuff into kebab-case because that was what I needed when I searched for case conversion utilities.

To convert all cases into kebab-case, I had to consider the possible cases. Here are the cases once again:

  • camelCase
  • PascalCase
  • snake_case
  • Sentence case
  • Title Case

Converting snake_case, Sentence case and Title Case into kebab-case is easy. I only need to do two things:

  1. Lowercase everything
  2. Replace _ and spaces with -

But I cannot begin by lowercasing everything if I wanted to support case conversion from camelCase and PascalCase. I would lose the word-break point.

So I had to begin by searching for the capital letters which denote the start of a new word (for camelCase and PascalCase). The easiest way is to loop through each letter and run a simple /[A-Z]/ regex. This regex searches for any letter that’s between A and Z.

function toKebab (string) {
return string
.split('')
.map((letter, index) => {
if (/[A-Z]/.test(letter)) {
// Capital letters
}
return letter
})
.join('')
}

Then I lowercased the capital letters and added a space in front of them. (It doesn’t matter whether I add space or _, both are fine since I’m going to replace them with - later).

function toKebab (string) {
return string
.split('')
.map((letter, index) => {
if (/[A-Z]/.test(letter)) {
return ` ${letter.toLowerCase()}`
}
return letter
})
.join('')
}

Note: I’m pretty sure there’s a regex that can do these three steps in one. It probably uses capturing groups and substitution, which I’m not familiar with. I didn’t try it since I didn’t have the time nor energy to research further. If you know a good regex for this, let me know!

This step converts the cases into the following:

  • camel case
  • pascal case
  • snake_case
  • sentence case
  • title case

There’s a space at the start of some cases. I removed them with trim.

function toKebab (string) {
return string
.split('')
.map((letter, index) => {
if (/[A-Z]/.test(letter)) {
return ` ${letter.toLowerCase()}`
}
return letter
})
.join('')
.trim()
}

This gives me the following:

  • camel case
  • pascal case
  • snake_case
  • sentence case
  • title case

I can now replace both _ and spaces with -. This can be done with two replace calls like this:

    1. First replace uses /_/g to replace all occurences of _.
    1. Second replace uses /\s+/ to replace all spaces into -. The + indicates “one or more”, so it matches the two spaces in title case.
export function toKebab (string) {
return string
// ...
.replace(/_/g, '-')
.replace(/\s+/g, '-')
}

I can combine both replace calls into a single regex with []. The square brackets indicate an OR value.

export function toKebab (string) {
return string
// ...
.replace(/[_\s]+/g, '-')
}

That gives me the this:

  • camel-case
  • pascal-case
  • snake-case
  • sentence-case
  • title-case

It even works for complicated mixed cases too. For example, if you try case_With-long name you’ll get case-with-long-name.

Converting anything to Sentence case

I worked on this utility next since I wanted to convert camelCase into Sentence case.

At first, I dreaded the thought of finding the similarities between all 6 cases again. It felt like a lot of work.

But I realized I can use my toKebab function to convert everything into kebab-case first. This takes advantage of the work I’ve already done.

I was against this idea at first because it seems like a “waste of resources” to run another function first from a performance standpoint. But I realized I was being idealistic. From a practical standpoint, it doesn’t have much impact on performance since the operations are really fast.

// Starting with toKebab
function toTitle (string) {
return toKebab(string)
}

Now I just need to convert kebab-case to Title Case.

Here, I only need to do the following:

  1. Split the string at -. This gives me an array of words.
  2. Capitalize the first letter of each word.
  3. Join the array with space.
export function toTitle (string) {
return toKebab(string)
.split('-')
.map(word => {
return word.slice(0, 1).toUpperCase() + word.slice(1)
})
.join(' ')
}

And I’m done!

Converting anything into Sentence Case

It’s equally easy to convert all cases into Sentence case. Once again, I started by converting things into kebab-case.

export function toSentence (string) {
return toKebab(string)
}

Now I only need to convert kebab-case into Sentence case. There are two things to do:

  • Capitalize the first letter
  • replace - with space.

I can do either step first. In this case, I chose to do the replace step first since I can chain it after toKebab.

export function toSentence (string) {
const interim = toKebab(string)
.replace(/-/g, ' ')
return interim.slice(0, 1).toUpperCase() + interim.slice(1)
}

Convert anything into camelCase

Finally, I want to be able to convert any string back into camel case.

I start with toKebab as usual.

export function toCamel (string) {
return toKebab(string)
}

At this point, I only need to convert kebab-case into camelCase.

I can do this by:

  1. Splitting the word at each -. This creates an array of words.
  2. Loop through the array and capitalize the first letter if it’s not the first word.
function toCamel (string) {
return toKebab(string)
.split('-')
.map((word, index) => {
if (index === 0) return word
return word.slice(0, 1).toUpperCase() + word.slice(1).toLowerCase()
})
.join('')
}

Simple as that!

Case Conversion Library

I placed added these case-conversion utilities into my JavaScript repository. You can grab them if you want them :)

Why we should use Ergonomic keyboards

Normal keyboards create tension in the wrists, which eventually lead to backaches. In this article, I explain how that connection happens and why we should use ergonomic keyboards.

What’s the difference between an Interface and an API?

I used to think JavaScript doesn’t have Interfaces because it doesn’t have the Interface keyword, unlike Java.

Interface keyword in Java

But JavaScript DOES have interfaces. I found out about this when I tried Googling for the location API, which turned out to the location Interface 🤦‍♂️.

Location interface.

I was confused. What the hell is the difference between an interface and an API? I sat down and figured it out (as usual). I want to share my newfound understanding with you in this article.

Let’s begin with interfaces.

Understanding JavaScript Prototype

JavaScript is said to be a Prototype-based language. So “prototypes” must be an important concept, right?

Today I’m going to explain what Prototypes are, what you need to know, and how to use Prototypes effectively.

Testing JavaScript Performance

I was curious about testing JavaScript performance and did some research on it.

When I talk about JavaScript performance here, I’m not talking about things like time-to-first-byte, time-to-interaction, etc… I’m talking about raw computing speed – how long does function X run compared to function Y.

I discovered we can use two methods to test performance – performance.now and Date.now. I was curious about the difference between them, so I made some experiments to document my findings.

The procedure

The procedure for testing performance is simple. There are three steps:

  1. Check the current timestamp
  2. Run some operations
  3. Check the timestamp again

The difference between the two timestamps will be the amount of time needed to run the operations.

Here’s what this process looks like in code:

const start = performance.now()
// Do stuff
const end = performance.now()

const elapsed = end - start console.log(elapsed)

Performance.now vs Date.now

performance.now is said to generate a Dom high-res timestamp, which means it’s going to be more accurate than Date.now.

Unfortunately, browsers have to round off this timestamp because of security issues, so it doesn’t make much of a difference in the end (according to my findings).

To help with the tests, I created a perf function.

function perf (message, callback, loops = 1) {
const startTime = performance.now()
while (loops) {
callback()
loops = loops - 1
}
const endTime = performance.now()
const elapsed = endTime - startTime
console.log(message, elapsed)
}

I also created a Date.now equivalent and I named it perfDate

function perfDate (message, callback, loops = 1) {
const startTime = Date.now()
while (loops) {
callback()
loops = loops - 1
}
const elapsed = Date.now() - startTime
console.log(message, elapsed)
}

Experiments and Findings

I tested both performance.now and Date.now with a simple operation:

function test () {
return 1 + 1
}

While testing, I realised there’s no point in testing one operation because of two reasons.

First, performance.now can measure operations in microseconds but Date.now can’t. So we won’t be able to see the differences between them.

Time taken for one operation in Chrome

Second, performance.now gets rounded off to the nearest millisecond in Safari and Firefox. So there’s no point comparing anything that takes less than 1ms.

Firefox rounds performance.now values to nearest millisecond

I had to increase the tests to 10 million operations before the numbers begin to make sense.

10 million operations.

Finding #1: Performance.now vs Date.now

I ran this code:

const count = 10000000
perf('Performance', _ => { return 1 + 1 }, count)
perfDate('Performance', _ => { return 1 + 1 }, count)
Initial test

Here, I found no major difference between performance.now and Date.now.

However, performance.now seems slower on Safari and Firefox. performance.now also gets rounded to the nearest millisecond on Safari and Firefox.

Finding #2: Chrome takes time to define functions

I tried stacking perf and perfDate functions to see if there were any differences. The results startled me.

const count = 10000000

perf(‘Performance’, _ => { return 1 + 1 }, count) perf(‘Performance’, _ => { return 1 + 1 }, count) perf(‘Performance’, _ => { return 1 + 1 }, count)

perfDate(‘Date’, _ => { return 1 + 1 }, count) perfDate(‘Date’, _ => { return 1 + 1 }, count) perfDate(‘Date’, _ => { return 1 + 1 }, count)

Stacked test.

Second and Third tests on Chrome for both perf and perfDate jumped from 8ms to 80ms. That’s a 10x increase. I thought I was doing something wrong!

I discovered this increase was caused by defining functions on the fly. If I used a predefined function, the numbers reduced back to 8ms.

function test () {
return 1 + 1
}

const count = 10000000

perf(‘Performance’, test, count) perf(‘Performance’, test, count) perf(‘Performance’, test, count)

perfDate(‘Date’, test, count) perfDate(‘Date’, test, count) perfDate(‘Date’, test, count)

Stacked results when using predefined function.

Note: I also found out that Node’s performance.now has the same behaviour as Chrome’s performance.now.

Finding #3: It’s impossible to get an average result

I realised each performance.now and Date.now resulted in different values. I wanted to get an average of the results, so I added another loop to perf.

(I did the same to perfDate too).

function perf (message, callback, loops = 1, rounds = 10) {
const results = []

while (rounds) { const startTime = performance.now()

while (loops) { callback() loops = loops - 1 }

const endTime = performance.now() const elapsed = endTime - startTime

results.push(elapsed) rounds = rounds - 1 }

const average = results.reduce((sum, curr) => curr + sum, 0) / results.length console.log(message) console.log(‘Average’, average) console.log(‘Results’, results) }

But the results were strange: the elapsed timing for the second loop onwards dropped to zero. This happened for both perf and perfDate.

It also happened for all three browsers!

I’m not sure what’s wrong here. If you know why, please tell me!

Conclusion

Both performance.now and Date.now can be used to test for JavaScript performance. There isn’t a major difference between these two methods though.

When testing on Chrome, make sure you use predefined functions. Don’t define functions on the fly or you’ll get inaccurate tests.

Hold on while i sign you up…

🤗
Woohoo! You’re in!
Now, hold on while I redirect you.