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.

Categories
JavaScript Tips

Useful JavaScript Tips — This, Modules, and Functions

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.

Returning Objects to Enable Chaining of Functions

We can return objects in methods to let us chain functions.

For instance, we can do that by writing:

const obj = {
  height: 0,
  width: 0,
  setHeight(height) {
    this.height = height;
    return this;
  },
  setWidth(width) {
    this.width = width;
    return this;
  }
}

Then we can call it by running:

obj.setHeight(100).setWidth(300);

and we get that obj.height is 100 and obj.width is 300.

Also, we can do the same for classes.

For instance, we can write:

class Obj {
  setHeight(height) {
    this.height = height;
    return this;
  }

  setWidth(width) {
    this.width = width;
    return this;
  }
}

Then we can write:

new Obj().setHeight(100).setWidth(300)

Safe String Concatenation

We can use the concat method to concatenate strings.

For instance, we can write:

const one = 1;
const two = 2;
const three = '3';
const result = ''.concat(one, two, three);

Then we get that result is '123' .

Run a Module if it’s not Required

We can check the module.parent property to see if a JavaScript file is required by another file.

For instance, we can write:

if (!module.parent) {
  // run code ...
} else {
  module.exports = app;
}

If module.parent is falsy, then we run the code inside the if block.

Otherwise, we export the module members so that they can be required.

Passing Arguments to callback Functions

We can pass arguments to callback function if we create a function that returns the callback with the arguments included.

For instance, we can write:

const callback = (a, b) => {
  return () => {
    console.log(a + b);
  }
}

Then we can write:

const x = 1, y = 2;
document.getElementById('foo').addEventListener('click', callback(x, y));

We called callback to return a function that adds the 2 arguments together.

This means that we can include those arguments in the callback.

Using indexOf to Check if Something is Included

We can use the indexOf method to check if a string has some substring.

For instance, we can write:

'something'.indexOf('thing') !== -1

or:

'something'.indexOf('thing') >= 0

indexOf returns -1 if a substring isn’t found.

If it’s found, then it returns the first index of the substring.

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

'something'.includes('thing');

Then true is returned if the substring is found.

So, it would return true .

The same methods are also in arrays.

So we can write:

['foo', 'bar'].indexOf('foo') !== -1

or:”

['foo', 'bar'].indexOf('foo') >= 0

or:

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

Arrow Functions

We can use arrow functions to make our code shorter if our function doesn’t have to have its own this .

For instance, we can write:

const squared = arr.map((x) => x ** 2);

We have an implicit return for single statement arrow functions.

It’s much shorter to use them.

However, bind , call , or apply won’t work with them since they don’t have their own this .

Also, we can’t use the arguments object inside it, but that isn’t much of a loss.

Measuring Performance of Our Code

We can use console.time and console.timeEnd to measure the performance of our code.

For instance, we can write:

console.time("populate array");
let arr = Array(100),
    len = arr.length,
    i;

for (i = 0; i < len; i++) {
    arr[i] = new Object();
};
console.timeEnd("populate array");

We start measuring with console.time .

Then we run the code that we want to measure the performance of.

Then we called console.timeEnd to stop measuring.

Making Parameters Mandatory

We can make parameters mandatory if we throw errors in the function that returns the default parameter value.

For instance, we can write:

const err = ( message ) => {
  throw new Error( message );
}

const getSum = (a = err('a is required'), b = err('b is not required')) => a + b

We can call functions when we assign default parameter values.

Therefore, we can throw errors if they’re not set by running the err function.

err only runs if the parameter isn’t set.

Conclusion

We can make chainable functions if we return this in our object or class methods.

Also, we can sure parameters are set if we run a function that throws errors on the right side of the assignment operator.