Categories
JavaScript Tips

Useful JavaScript Tips — Loops and Sorting Dates

Like any kind of apps, JavaScript apps also have to be written well. Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some tips we should follow to write JavaScript code faster and better.

Break Out of a for Loop

If we want to end a for loop early, we can use the break keyword.

For instance, we can write:

for (const val of list) {
  console.log(val);
  if (val === 'b') {
    break;
  }
}

If val is 'b' then we end the loop with break .

We can also do the same with an old for loop:

for (let i = 0; i < list.length; i++) {
  console.log(list[i]);
  if (list[i] === 'b') {
    break;
  }
}

We do the same thing, except it’s longer because of the indexes.

Check if an Object is Empty

We can check if an object is empty with the Object.entries method. It returns the non-inherited key-value pairs in an object.

Therefore, we can write:

Object.entries(obj).length === 0

to check if obj is empty by checking the array returned by Object.entries ‘s length.

It’s a good idea to check that obj is actually by adding:

obj.constructor === Object

Lodash also has the isEmpty function to do the same thing.

We can write:

_.isEmpty(obj)

to do the check.

Return the Result of an Async Function

An async function returns a promise with the resolved value of the promise.

For instance, if we write:

const getJSON = async () => {
  const response = await fetch('./file.json')
  return response
}

then we return a promise that resolves to the response object. We can then use it with other async functions or call then on it.

Check if a JavaScript Array has a Given Value

We can use the includes method to check if an array has the given value.

For instance, we can write:

['red', 'green'].includes('red');

Then we can check if 'red' is in the array it’s called on. It should return true since it’s included in the array. If the value in the argument isn’t included, then it returns false .

Rename Fields When Object Destructuring

We can rename fields when we’re destructuring objects. To do that, we can use the : symbol to do it.

For instance, we can write:

const person = {
  firstName: 'james',
  lastName: 'smith'
}

const { firstName: name, lastName } = person;

Then we renamed firstName to name. So name is 'james'.

Using Symbols

We can use symbols to create an identifier that’s always unique. Each symbol that’s created won’t be the same even if they have the same content.

For instance:

Symbol() === Symbol()

returns false .

Symbol('foo') === Symbol('foo')

is also false .

We can use them as property identifiers.

For instance, we can write:

const foo = Symbol('foo');
const obj = {
  [foo](){
    //...
  }
}

We can also write:

const foo = Symbol('foo');
class Bar {
  [foo](){
    //...
  }
}

We can use symbols in both objects and classes as identifiers.

Public Class Fields

We can add public class fields by putting them in constructors or methods.

For instance, we can write:

class Foo {
  constructor() {
    this.count = 0
  }
}

Sorting an Array by Date

To sort an array by date, we can use the sort method and compute the difference between the dates 2 entries and return it.

For instance, given the following array:

const tasks = [{
    title: 'eat',
    date: new Date('2020-06-23')
  },
  {
    title: 'drink',
    date: new Date('2020-06-10')
  },
  {
    title: 'sleep',
    date: new Date('2020-06-22')
  }
]

We can sort it by date descending order by writing:

tasks.sort((a, b) => +b.date - +a.date);

sort sorts an array in place.

The + operator converts dates to UNIX timestamps so that we can compute their difference.

If the difference is more than 1, then sort reverses the order of the 2 entries.

So we get:

[
  {
    "title": "eat",
    "date": "2020-06-23T00:00:00.000Z"
  },
  {
    "title": "sleep",
    "date": "2020-06-22T00:00:00.000Z"
  },
  {
    "title": "drink",
    "date": "2020-06-10T00:00:00.000Z"
  }
]

as the value of tasks .

We can flip a and b around to sort tasks in date ascending order.

To make a copy of tasks before sorting, we can use the spread operator or slice as follows:

const sortedTasks = [...tasks];
sortedTasks.sort((a, b) => +b.date - +a.date);

or:

const sortedTasks = tasks.slice();
sortedTasks.sort((a, b) => +b.date - +a.date);

Conclusion

We can use break to end a loop early.

To sort objects with dates, we can return the difference between the timestamps.

Also, we can check if an object is empty with Object.entries to return an array of key-value pairs and use the length property.

Categories
JavaScript Tips

Useful JavaScript Tips — Strings, Arrays, and Images

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some tips we should follow to write JavaScript code faster and better.

Cut a String into Words

To divide a string into words, we can use the split method.

For instance, we can write:

const text = "hello james smith";
const arr = text.split(" ");

Then text would be split into an array of strings by their spaces.

So arr would be [“hello”, “james”, “smith”] .

Load an Image into the Canvas

We can load an image into the canvas by using the drawImage method of the canvas context.

For instance, if we have the following canvas:

<canvas width="300" height="300"></canvas>

and image element:

<img id='cat' style='visibility: hidden' src='http://placekitten.com/200/200' />

We can write:

const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
const img = document.getElementById("cat");
context.drawImage(img, 90, 90, 50, 60, 10, 10, 50, 60);

The first argument of drawImage is the image element.

The 2nd argument is the x coordinate of the top left corner of the image.

The 3rd is the y coordinate of the top left corner.

The 4th is the width of the sub-rectangle of the source image.

The 5th is the height of the sub-rectangle of the source image.

The 6th is the x-coordinate of the destination canvas to place the top-left corner of the source.

The 7th is the y coordinate of the top left corner.

The 8th is the width of the image to the destination canvas.

The last one is the height of the image in the destination.

Slowing Down a Loop

We can slow down a loop with promises.

First, we create our own sleep function with the setTimeout function:

const sleep = (ms) => {
  return new Promise(resolve => setTimeout(resolve, ms))
}

We return a promise that runs setTimeout and call resolve . ms is the delay in milliseconds.

Then we can run the sleep function in a loop by running:

const list = [1, 2, 3];
(async () => {
  for (const item of list) {
    await sleep(1000);
    console.log(item)
  }
})();

We have an array list , which we loop through in an async function.

In the loop body, we called sleep with 1000 to delay the loop by 1 minute.

Then we log the item with the console.log.

Get the First n Items in an Array

To get the first n items in an array, we can use the slice method.

For instance, we can write:

const arr = [1, 2, 3, 4, 5];
const newArray = arr.slice(0, 2);

to return the first 2 array entries from arr in a new array.

So newArray would be [0, 1] .

Convert an Array to a String

We can call the toString method to convert an array to a string.

For instance, we can write:

const list = [1, 2, 3];
const str = list.toString();

Then we get “1,2,3” as the value of str .

It’s not very flexible since it converts it the way it likes to.

To add more flexibility, we can use the join method.

For instance, we can write:

const list = [1, 2, 3];
const str = list.join();

to concatenate the entries of the array into a string.

We can pass in a separator to separate the entries.

So we can write:

const list = [1, 2, 3];
const str = list.join(', ');

To use the comma as a separator.

Flattening Arrays

We can flatten arrays with flat and flatMap .

For instance, we can write:

const animals = ['dog', ['cat', 'wolf']];
const flattened = animals.flat();

We called flat , which is a built-in array method.

Then we see that flattened is [“dog”, “cat”, “wolf”] .

flat can flatten arrays at any level.

If we pass in 2, then it flattens 2 nesting levels.

If we pass in Infinity , then flattening is done recursively.

So if we call:

const animals = ['dog', [['cat', 'wolf']]];
const flattened = animals.flat(2);

We get the same result.

If we write:

const animals = ['dog', [['cat', 'wolf']]];
const flattened = animals.flat(Infinity);

We get complete flattening, which also means the same result.

Conclusion

We can flatten arrays easily with flat .

Also, we can load images from the img tag into a canvas with drawImage .

To pause execution of JavaScript code, we can use setTimeout with promises.

Categories
JavaScript Tips

Useful JavaScript Tips — Dark Mode and Slices

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some tips we should follow to write JavaScript code faster and better.

Checking for Dark Mode in Browsers

We can check for dark mode in browsers using the matchMedia method.

For instance, we can write:

window.matchMedia('(prefers-color-scheme: dark)').matches

We can also attach a listener to listen for mode changes.

For instance, we can write:

window
  .matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', event => {
    if (event.matches) {
      //dark mode
    } else {
      //light mode
    }
  })

event.matches matches dark mode before running the if block.

Check if an Element is a Descendant of Another

We can check if an element is a descendant of another by using the parentNode property.

For instance, we can create a function that traverses the DOM tree to check if an element has the given node.

We can write:

const isDescendant = (el, parent) => {
  let child = el;
  while (child = child.parentNode) {
    if (child === parent) {
      return true
    }
  }
  return false
}

We have a function that takes el an parent which are DOM elements.

Then we use a while loop to loop to traverse from child , which starts with el and traverse up the tree by assigning the parentNode property value to child .

Then inside the loop, we check if they’re the same element with === .

If there’s no element up the tree that equals parent then we return false .

Therefore, if we have the following HTML:

<div>
  <p>
    foo
  </p>
</div>

Then the following logs true :

const p = document.querySelector('p');
const div = document.querySelector('div');
console.log(isDescendant(p, div))

On the other hand, if we have:

<div>

</div>

<p>
  foo
</p>

Then the same code would log false .

Remove the First Character of a String in JavaScript

To return a new string with the first character of the original one removed, we can use the slice method.

For example, we can write:

const text = 'foo'
const shortened = text.slice(1);

Then shortened would be 'oo' .

Remove the Last Character of a JavaScript String

Removing the last character of a JavaScript string is a bit harder.

But we can use the slice method to do it.

For instance, we can write:

const text = 'foo'
const shortened = text.slice(0, -1);

We pass in a second argument with the end index of the slice.

The last index isn’t included in the returned string.

-1 means the last index of the string. Negative indexes go from right to left.

So -2 would be the second last index, -3 the 3rd last and so on.

Therefore, shortened would be 'fo' .

Add Text to an HTML Canvas

We can add text to an HTML canvas by using the fillText method of the canvas context.

Given that we have the following canvas:

<canvas width="300" height="300"></canvas>

We can write the following to add some text:

const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
context.fillText('hello world', 100, 100);

fillText ‘s 1st argument is the text itself.

The 2nd and 3rd arguments are the x and y coordinates of the point which to start drawing the text in pixels.

Divide an Array in Half

We can divide an array in half by using the Math.ceil and slice methods.

For instance, we can write the following:

const list = [1, 2, 3, 4, 5, 6, 7, 8];
const half = Math.ceil(list.length / 2);
const firstHalf = list.slice(0, half);
const secondHalf = list.slice(-half);

slice returns a new array, so we can use it to slice it according to the start and end indexes we give them.

half is the index of the halfway point.

If half is used as the end index of the slice, it’s excluded. If it’s used as the starting index, then it’s included.

So firstHalf has entries from the first to the one before the one with index half .

And secondHalf has entries from index half to the end.

Therefore, firstHalf would be [1, 2, 3, 4] .

And secondHalf is [5, 6, 7, 8] .

Conclusion

We can check dark mode in browsers with matchMedia .

Also, we can extract parts of a string or an array with slice .

We can use the parentNode property to get the parent of a DOM element.

Categories
JavaScript Tips

Useful JavaScript Tips — Properties and Arrays

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some tips we should follow to write JavaScript code faster and better.

Check if a property is in an Object

There are a few ways that we can use to check if a property is in an object.

For instance, we can use the hasOwnProperty method as follows:

obj.hasOwnProperty('name');

hasOwnProperty is a method of an object that’s inherited from Object.prototype .

It returns true if 'name' is a non-inherited property of an object/

Also, we can use the in operator to check if a property is part of the object, including in prototypes.

For instance, if we write:

'valueOf' in obj;

Then it would return true since valueOf is inherited from the obj ‘s prototype.

Template Strings

Template strings are great form combing various expressions into a string.

Instead of concatenation, we can use template strings.

For instance, instead of writing:

const firstName = 'jane';
const lastName = 'smith';
const name = firstName + ' ' + lastName;

We can write:

const firstName = 'jane';
const lastName = 'smith';
const name = `${firstName} ${lastName}`;

It’s shorter and there are no plus signs.

Converting a Node List to an Array

We can use the spread operator to convert a node list to an array.

For instance, we can write:

const nodeList = document.querySelectorAll('div');
const nodeArr = [...nodeList];

We can do this because a node list is an array-like iterable object, which means that it can be converted with the spread operator to an array.

Now we can use any array methods on a node list, making our lives much easier.

Write a Method that Works with Both Arrays and a Single Value

We can write a method that works with both arrays and a single value by checking if it’s an array.

For instance, we can write:

const foo = (val) => {
  if (Array.isArray(val)){
    //...
  }
  else {
    //...
  }
}

We used the Array.isArray method to check if val is an array.

Then we can have a function that works with both arrays and a single value.

Hoisting

We should be aware of the hoisting of function declarations.

Hoisting means that the value is pulled to the top of the file.

Function declarations are hoisted.

So if we have:

function foo(){
  //...
}

Then it can be called anywhere in the file.

Sorting Strings with Accented Characters

To sort strings with accented characters, we can use the localeCompare method to order them properly.

For instance, we can write:

`['`marrón`', 'árbol', '`dulce`', 'fútbol'].sort((a, b) => a.localeCompare(b));`

Then we can sort them without hassle.

We get:

["árbol", "dulce", "fútbol", "marrón"]

which is what we expect.

Likewise, we can use the Intl.Collator method as follows to do the same thing:

`['`marrón`', 'árbol', '`dulce`', 'fútbol'].sort(Intl.Collator().compare);`

It takes 2 arguments with the strings to compare and return the same thing as localeCompare, so we can pass the function straight in.

It’s faster than localeCompare when comparing a large number of strings.

Therefore, when we compare non-English strings, we should use these 2 functions to compare them.

Improving Nested Conditionals

We can eliminate nested conditionals by using the switch statement.

For instance, instead of writing:

if (color) {
  if (color === 'black') {
    doBlack();
  } else if (color === 'red') {
    doRed();
  } else if (color === 'blue') {
    doBlue();
  } else {
    doSomething();
  }
}

We can use the switch statement instead:

switch(color) {
  case 'black':
    doBlack();
    break;
  case 'red':
    doRed();
    break;
  case 'blue':
    doBlue();
    break;
  default:
    doSomething();
}

It’s shorter and we don’t need to check whether color is falsy before doing the other checks.

This is because the default clause takes care of the falsy check.

Add Item Inside an Array

We can add an item by using the concat method.

For instance, we can write:

const arr = [1,2,3];
const four = arr.concat(4);

concat returns the array with the new item appended to it.

So we get [1, 2, 3, 4] for four .

We can use push to add an item to an array in place.

For instance, we can write:

const arr = [1,2,3];
arr.push(4);

arr is now [1, 2, 3, 4] .

Conclusion

We can use concat or push to add items to an array.

Also, we can use in or hasOwnProperty to check if a property is in an object.

If we sort string arrays with strings that have accents, then we need to use localeCompare or Intl.Collator().compare.

Categories
JavaScript Tips

JavaScript Tips — Converting Byte Sizes, Removing Blank Attributes, and More

Like any kind of apps, there are difficult issues to solve when we write JavaScript apps.

In this article, we’ll look at some solutions to common JavaScript problems.

Difference Between DOMContentLoaded and Load Events

There’s a difference between DOMContentLoaded and load events.

DOMContentLoaded event is fired when the document is loaded and parsed without waiting for resources like stylesheets, images, and subframes to finish loading.

The load event waits for everything to finish loading.

Plus Symbol Before a Variable

The + operator converts a non-numeric variable to a number.

For instance, if we have:

const str = '123';
const num = +str;

Then num is 123.

Determine if String is in an Array in JavaScript

We can use the indexOf method to check if a string is in an array.

For instance, we can write:

['foo', 'bar', 'baz'].indexOf(str) > -1

We can call indexOf to check if str is included in the ['foo', 'bar', 'baz'] array.

indexOf return -1 if it’s not in the array and the index if it is.

Also, we can use the includes method to do the same thing:

['foo', 'bar', 'baz'].includes(str)

It returns true if it’s included and false if it’s not.

Convert Size in Bytes to KB, MB, GB, etc. in JavaScript

We get convert the magnitude of bytes to the KB, MB, etc. by dividing the number of bytes with the power of 1024 to the power of the unit that we’re converting to.

For instance, we can write:

const formatBytes = (bytes, decimals) => {
  if (bytes == 0) {
    return "0 Byte";
  }
  const k = 1024;
  const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(decimals))} ${sizes[i]}`;
}

We return '0 bytes' is bytes is 0.

To convert the bytes to a given unit, we can divide it, by the power of 1024.

i is the index of the sizes array that we want to get, which is also the exponent that we want to raise 1024 to.

If we divide by 1024, we get the size in KB.

And if we divide by 1024 ** 2 , we get the size in MB, and so on.

Now we get the size and the corresponding unit.

Include JS File in Another JS File

We can include one JS file in another JS file by creating a script tag dynamically.

For instance, we can write:

const script = document.createElement('script');
script.src = '/path/to/script';
document.head.appendChild(script);

to create the script tag.

Then we append it to the head element to load the script.

Remove Blank Attributes from an Object in Javascript

We can remove blank attributes from an object in JavaScript by getting the keys with the Object.keys method.

Then we can use delete to delete the keys that have empty values.

For instance, we can write:

for (const key of Object.keys(obj)) {
  if (obj[key] === null || typeof obj[key] === 'undefined') {
    delete obj[key];
  }
}

We loop through the keys with a for-of loop.

In the loop body, we check for null and undefined .

Then we use delete to delete the property with values null or undefined .

Sort an Array of Objects by Single Key with Date Value

If we have an array of objects with a property that is a date string, we can use the sort method to sort the array by the date string property.

For example, if we have the following array:

const arr = [{
    updatedAt: "2012-01-01T06:25:24Z",
    foo: "bar"
  },
  {
    updatedAt: "2012-01-09T11:25:13Z",
    foo: "bar"
  },
  {
    updatedAt: "2012-01-05T04:13:24Z",
    foo: "bar"
  }
]

Then we can write:

const sorted = arr.sort((a, b) => {
  const updatedAtA = new Date(a.updatedAt);
  const updatedAtB = new Date(b.updatedAt);
  return updatedAtA - updatedAtB;
});

We have a callback that subtract updatedAtA and updatedAtB .

This works because before they’re subtracted, they’re converted to their timestamp values first.

Therefore, we can do the sorting as a number will be returned.

Conclusion

DOMContentLoaded and load are different events.

We can sort dates directly.

The + operator can be used to convert to numbers.

We can convert bytes to different units by doing some division.