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.

Categories
JavaScript Tips

Useful JavaScript Tips — Variables 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.

Assignment Operators

We can use compound assignment operators to make updating the values of numeric variables easier.

There are the += , -= , *= , /= , and %= operators which we can use to update numeric variables to whatever value we want based on the current one.

For instance, we can write:

x += 2;

Then we update the value of x by incrementing the current value by 2.

It’s the same as:

x = x + 2;

Likewise, we can do the same with the rest.

-= is subtraction.

*= is multiplication.

/= is for division.

And %= is for getting the remainder based on the current value.

So:

x %= 2;

is the same as:

x = x % 2;

Then we get the remainder of x divided by 2 based on the current value of x and reassigns it.

Converting Truthy or Falsy Values to Boolean

We can use the !! operator to convert anything to a boolean.

For instance, we can write:

!!""
!!0
!!null
!!undefined
!!NaN

They’re all falsy, so they all return false .

Other operands will return true . For instance, if we have:

!!"hi"

then that would return true .

Currying

Curry is the action of converting a function that takes multiple arguments into a series of functions that take a single argument.

It’s useful for creating functions that have some arguments applied and reuse that.

For instance, if we have an add function:

const add = (x, y) => {
  return x + y;
}

Then we can curry the function by writing:

const curriedAdd = (x) => {
  return (y) => {
    return x + y;
  }
}

Then we can call it by writing:

curriedAdd(1)(2)

and get 3.

Partial Application

We can partially apply arguments into a function by writing:

const plus10 = (y) => {
  return 10 + y;
}

Then we can write:

plus10(3);

Then we get 13.

To generalize this, we can write:

const partApply = (f, x) => {
  return (y) => {
    return f(x, y);
  }
}

Then we can call partApply by passing in a function for f and a value for x .

For instance, we can write:

const plus10 = partApply(add, 10);

Then we get 13 if we call plus10(3) since 10 is applied as the first argument.

Filtering and Sorting a List of Strings

We can sort filter strings with the filter method.

We can get the ones that we return an array that has words that have the same length as its index by writing:

const filtered = words
  .filter((word, index) => {
    return word.length > 2
  })

So if we have:

const words = ['do', 'if', 'foo', 'bar'];

Then we get:

["foo", "bar"]

Then we can call sort without any callback to sort strings since that’s how sort sorts array items without a callback.

So we can chain them by writing:

const filtered = words
  .filter((word, index) => {
    return word.length > 2
  })
  .sort();

Then we get [“bar”, “foo”] for filtered .

Using Immediately Invoked Function Expressions (IIFEs)

We can create and use IIFEs to enclose variables in a function so that they stay private.

For instance, we can write:

(() => {
  let x = 1;
  //...
})()

Then x stays inside the function.

This is one way to create private variables in a function.

Quick Way to Convert Numbers

To convert numbers easily, we can use the + operator to convert anything to a number.

For instance, we can write:

const one = +'1';

Then one is the number 1 instead of string '1' since we used the + operator on it.

Shuffle an Array

We can shuffle an array by using the sort method and return a random number that can be positive or negative so that we can shuffle them.

For instance, we can write:

const arr = [1, 2, 3];
arr.sort(() => -1 + (Math.random() * 2));

sort sorts an array in place, so we get a different value of it.

Returning -1 + (Math.random() * 2) will make the callback return something -1 and 1.

Conclusion

We can use various methods to filter and sort arrays.

Also, we can use assignment operators to make assignment statements shorter.