Javascript Archives | Justin Joyce https://justinjoyce.dev/category/javascript/ Practical tips and tutorials about software development. Wed, 10 Jan 2024 01:57:32 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://justinjoyce.dev/wp-content/uploads/2023/10/cropped-android-chrome-512x512-1-32x32.png Javascript Archives | Justin Joyce https://justinjoyce.dev/category/javascript/ 32 32 Check if key exists in Javascript object https://justinjoyce.dev/check-if-key-exists-in-javascript-object/ https://justinjoyce.dev/check-if-key-exists-in-javascript-object/#comments Mon, 30 Oct 2023 17:59:00 +0000 https://justinjoyce.dev/?p=1441 To check if a key exists in a js object, you can: compare the key's value to undefined, use .hasOwnProperty, or use "key in object" syntax. Each method behaves a bit differently, so let's do some examples.

The post Check if key exists in Javascript object appeared first on Justin Joyce.

]]>
To check if a key exists in javascript, you have a few options:

  1. Compare the key’s value to undefined
  2. Use object.hasOwnProperty
  3. Use Javascript’s “in” operator

Each method behaves slightly differently, so let’s do some examples of each.

Compare the key’s value to undefined

If you try to access a key that does not exist on a javascript object, the returned value will be undefined1. Let’s see that in code:

const car = { make: "toyota", model: "camry" };
car.make; // "toyota"
car.year; // undefined

In other words, if you access an object key and receive undefined back, that key was probably2 not present on the object.

if (car.year === undefined) {
  console.log("year is not present");
} else {
  // go ahead and use the year
}

If you have nested keys, however, you might run into issues:

const car = { make: "toyota", model: "camry" };

// This will result in an exception
if (car.details.mpg === undefined) {
  console.log("MPG not present");
}

// Uncaught TypeError: Cannot read properties of undefined

The TypeError in the example above is because the car object didn’t contain details. So car.details returned undefined, and you can’t do undefined.mpg. To prevent this issue with nested objects, use optional chaining ?..

Use optional chaining for nested keys

Continuing the car example above, let’s say you’re not even sure you have the car object itself. You can use javascript’s optional chaining operator (?.) to protect yourself.

const car = { make: "toyota", model: "camry" };

// This won't blow up
if (car?.details?.mpg === undefined){
  console.log("MPG not present");
}
// "MPG not present"

// You can chain as far as you like
if (car?.details?.dimensions?.length?.inches) {
  // this is safe from errors, but I'd probably
  // ask questions in code review if I saw this
}

Optional chaining will account for both null and undefined values in the chain of object keys, so it should keep you fairly safe.

Object.hasOwnProperty

The hasOwnProperty method was written for exactly this use case.

const car = { make: "toyota", model: "camry" };

car.hasOwnProperty("make"); // true
car.hasOwnProperty("year"); // false

Additionally, hasOwnProperty will ensure the property truly belongs to this specific object, and isn’t something it inherited. Here’s an example:

const car = { make: "toyota", model: "camry" };

// All JS objects inherit the .toString() method
// But it is not specific to our car object
car.hasOwnProperty("toString");
// false

Use the Javascript in operator

Javascript’s in operator is not that widely-used in my experience, but it’s a nice way to test if a key exists in an object. Importantly, the in operator will return true for inherited properties, unlike hasOwnProperty above.

const car = { make: "toyota", model: "camry" };

"make" in car; // true
"year" in car; // false

// "in" will find inherited properties from the prototype chain
"toString" in car; // true

// If you need to be *sure* it's local to this object, use hasOwnProperty
car.hasOwnProperty("toString"); // false

It is a bit unusual to see this syntax structure in Javascript, which is probably why in isn’t too widely-used, but if you’re coming from Python it feels downright natural.


Helpful Links

Notes

  1. Unlike golang, which will give you the zero-value for that value’s type ↩
  2. I say probably because someone could deliberately set a value as undefined, but that would be very unusual as it violates the principal of least surprise. To indicate blank data, you would typically see null instead of `undefined`. ↩

The post Check if key exists in Javascript object appeared first on Justin Joyce.

]]>
https://justinjoyce.dev/check-if-key-exists-in-javascript-object/feed/ 1
Copy an object in Javascript https://justinjoyce.dev/copy-an-object-in-javascript/ Sat, 14 Oct 2023 16:01:17 +0000 http://mdh.tqp.mybluehost.me/?p=850 There are several ways to copy an object in Javascript, and they fall into two categories: shallow copies and deep copies. Before going deeper, it might be helpful to define the two: If you’re copying a simple Javascript object with top-level properties only, all copies will be deep copies, regardless of what method you use. […]

The post Copy an object in Javascript appeared first on Justin Joyce.

]]>
There are several ways to copy an object in Javascript, and they fall into two categories: shallow copies and deep copies. Before going deeper, it might be helpful to define the two:

  • Shallow copy: a copy of an object which shares references with the original. Modifying properties on either object might affect both.
  • Deep copy: a copy of an object which is entirely independent from the original. Modifying either object will not affect the other.

If you’re copying a simple Javascript object with top-level properties only, all copies will be deep copies, regardless of what method you use. If you have an object with nested properties, however, then you need to be more careful.

Let’s see some examples using a very common shallow-copying method, spread syntax:

// Simple, top-level properties only
const original = { name: "justin", age: 100 };
const copied = { ...original };

// These changes will not affect the original
copied.name = "frank";
copied.age = 50;

console.log(original);
// { name: "justin", age: 100 }

The two objects above are independent. Changing one has no effect on the other because those are all “top-level” properties; there are no nested values.

Here’s a more complicated example, where the objects are not independent:

// The "first" name property is now nested inside another object
const original = { name: { first: "justin" }, age: 100 };
const copied = { ...original };

// This change will affect both objects, this property is nested
copied.name.first = "frank";

// This change will NOT affect both, it isn't a nested property
copied.age = 50;

console.log(original);
// {name: {first: "frank"}, age: 100}

cosole.log(copied);
// {name: {first: "frank"}, age: 50}

In this example, changing a value on a nested property changed the value for both objects. That’s because when copying nested objects, javascript copies them by reference1, rather than creating entirely new objects.

Note: this holds true for Javascript Arrays also, since arrays are just objects. An array containing only top-level numbers or strings will always be deep copied. An array containing objects (or sub-arrays) will have each of those nested objects passed by reference unless you explicitly deep copy them.

Now that we have that explained, let’s move on to common copying methods.

Shallow Copies

Here are the common ways people shallow copy objects in JS:

Spread syntax

This is by far the most commonly-used method:

const original = { name: "justin", job: "dev" };
const copy = { ...original };

// You'll often see this with some properties overridden
const copyTwo = {...original, name: "joyce" };

// You can combine multiple objects
const copyThree = {
  ...original,
  ...another,
  ...somethingElse,
};

Object.assign

const original = { name: "justin", job: "dev" };
const copy = Object.assign({}, original)

// You override properties here too
const copyTwo = Object.assign({}, original, { name: "joyce" });

// You can combine multiple objects this way also
const copyTwo = Object.assign({}, original, another, somethingElse);

Array.concat

const one = [1];
const two = [{ two: 2 }];

// merged will be shallow
const merged = one.concat(two); // [ 1, { two: 2} ]

// this change will affect array 'two' also
merged[1].three = 3;

console.log(two); // [{ two: 2, three: 3 }]

The other common array methods also create shallow copies: Array.from() and Array.prototype.slice().

Deep Copies

The only surefire way to create a deep copy in javascript (without a library) is via the built-in JSON module.

const original = { name: { first: "justin", last: "joyce" }};
const copy = JSON.parse(JSON.stringify(original));

// 'copy' is now a completely independent object
// changing it will not affect the original
copy.name.first = "Tom";

console.log(original.name.first);
// "justin"

The JSON method requires that your original object is fully string-serializable, which is not always the case. Functions, for example, cannot be serialized via JSON, and won’t be copied this way:

const original = { func: () => console.log("hi"), name: "justin" };
const copy = JSON.parse(JSON.stringify(original));

// The 'func' param will be lost
console.log(copy);
// { name: "justin" }

In cases like this one, you might want to use a library function like lodash cloneDeep.


Helpful Links

  • For more on the limitations of deep-copying via JSON, head over to the Moz Docs.

Notes

  1. It’s essentially passing a pointer reference ↩

The post Copy an object in Javascript appeared first on Justin Joyce.

]]>
Flatten an array in Javascript https://justinjoyce.dev/flatten-an-array-in-javascript/ Sat, 24 Jun 2023 20:22:30 +0000 http://mdh.tqp.mybluehost.me/flatten-an-array-in-javascript/ Flattening an array means making it one-dimensional. The easiest way to flatten an array is via Array.prototype.flat. For many years, doing this in javascript required the use of concat, spread, or reduce. Not anymore. Flatten with Array.prototype.flat This method does exactly what you’d expect: By default, flat only flattens one level deep: But flat accepts […]

The post Flatten an array in Javascript appeared first on Justin Joyce.

]]>
Flattening an array means making it one-dimensional. The easiest way to flatten an array is via Array.prototype.flat.

// multi-dimensional array
const multiDimensional = [1, 2, [3, 4]];

// flat, one-dimensional array
const oneDimensional = [1, 2, 3, 4];

For many years, doing this in javascript required the use of concat, spread, or reduce. Not anymore.

Flatten with Array.prototype.flat

This method does exactly what you’d expect:

const multiDimensional = [1, 2, [3, 4]];

const oneDimensional = multiDimensional.flat();
// [1, 2, 3, 4]

By default, flat only flattens one level deep:

const multiDimensional = [1, [2, [3, 4]]];

// [3, 4] is nested two levels deep
multiDimensional.flat();
// [1, 2, [3, 4]]

But flat accepts an argument specifying depth:

const multiDimensional = [1, [2, [3, 4]]];
multiDimensional.flat(2);
// [1, 2, 3, 4]

That’s it!


Helpful Links

The post Flatten an array in Javascript appeared first on Justin Joyce.

]]>
Javascript map function https://justinjoyce.dev/javascript-map/ Mon, 27 Mar 2023 02:39:42 +0000 http://mdh.tqp.mybluehost.me/javascript-map/ The javascript map() function takes in a callback function, applies that callback function to each element of an array, and returns a new array containing the results. Many languages have a map function, and they all behave roughly this way. Javascript map basics map() accepts a single callback function, and passes each element of the […]

The post Javascript map function appeared first on Justin Joyce.

]]>
The javascript map() function1 takes in a callback function, applies that callback function to each element of an array, and returns a new array containing the results. Many languages have a map function, and they all behave roughly this way2.

Javascript map basics

map() accepts a single callback function, and passes each element of the calling array into that function:

const myArray = [1,2,3];

const timesTen = myArray.map(item => item * 10);
console.log(timesTen);
// [10, 20, 30]

Important note: don’t forget to return something, otherwise you’ll end up with a new array containing all undefined values:

const myArray = [1, 2, 3];

const timesTen = myArray.map((item) => {
    console.log(item * 10);
});
// 10
// 20
// 30

// We never returned anything
console.log(timesTen);
// [undefined, undefined, undefined]

Or maybe you have a more complicated function you want to use in your map. You can define it elsewhere and just pass it in like this, assuming it accepts a single parameter:

import { fancyFunction } from "~/utils";

const myArray = [1, 2, 3];

// Like any array method, you can pass your callback this way
const fancyArray = myArray.map(fancyFunction);

Map’s additional arguments

Typically when using map(), the callback function only takes in a single argument—the current array element. However, map actually makes three arguments available to the callback: the current array element, its index in the array, and the full calling array (which is the same every time).

Let’s look:

const myArray = ["a", "b", "c"];

myArray.map((element, idx, arr) => console.log(element, idx, arr));
// a 0 ["a", "b", "c"]
// b 1 ["a", "b", "c"]
// c 2 ["a", "b", "c"]

That’s about it. I hope this was helpful.


Helpful Links

Notes

  1. Not to be confused with javascript’s Map object ↩
  2. Python’s map leaves something to be desired, but you can just use list comprehensions instead ↩

The post Javascript map function appeared first on Justin Joyce.

]]>
Javascript forEach https://justinjoyce.dev/javascript-foreach/ Mon, 13 Mar 2023 23:00:20 +0000 http://mdh.tqp.mybluehost.me/javascript-foreach/ Javascript’s forEach method is one of its basic array methods, and it’s used all the time. It does as its name suggests, and performs a function for each element of an array: In the function above, I only accessed one argument, item. However, forEach actually makes 3 arguments available to its callback function if you […]

The post Javascript forEach appeared first on Justin Joyce.

]]>
Javascript’s forEach method is one of its basic array methods, and it’s used all the time. It does as its name suggests, and performs a function for each element of an array:

const myList = ["a", "b", "c"];
myList.forEach(item => console.log(item));
// "a"
// "b"
// "c"

In the function above, I only accessed one argument, item. However, forEach actually makes 3 arguments available to its callback function if you want them:

const myList = ["a", "b", "c"];
myList.forEach((item, index, list) => {
    console.log(item, index, list);
});

// "a", 0, ["a", "b", "c"]
// "b", 1, ["a", "b", "c"]
// "c", 2, ["a", "b", "c"]

ForEach cannot be stopped early

This is the major gotcha with forEach: it will always call your function once per array element, it cannot be stopped. Put another way, you cannot break a forEach. Consider this case, where you want to abort a for loop early:

const myList = ["a", "b", "c"];

// a traditional for loop can be broken early
for (let item of myList) {
    console.log(item);
    if (item === "a") {
        console.log("a found, terminating loop");
        break;
    }
}
// "a"
// "a found, terminating loop"

If you use forEach, you can’t stop the loop:

const myList = ["a", "b", "c"];
myList.forEach((item) => {
    console.log(item);
    if (item === "a") {
        console.log("a found, terminating loop");
        return;
    }
});
// "a"
// "a found, terminating loop"
// "b"
// "c"

Other notes about forEach

ForEach is not designed for use with async functions, even if you properly declare it as async and use await within the function body. This isn’t too surprising given how javascript generally handles async operations, but it is strange to see async / await not having their intended effects. For a full example of this behavior and a few more potential gotchas, check out the Moz docs page for forEach.

The post Javascript forEach appeared first on Justin Joyce.

]]>
Insert into javascript array at a specific index https://justinjoyce.dev/insert-into-javascript-array-at-a-specific-index/ Wed, 01 Feb 2023 00:03:31 +0000 http://mdh.tqp.mybluehost.me/insert-into-javascript-array-at-a-specific-index/ There are two options when inserting into an array in javascript: slice() and splice(). Array.prototype.slice Array.prototype.slice returns a copy of a portion of an array, like so: Let’s say we want to insert c where it belongs in this list, between b and d. The three dots ... in the above example are known as javascript spread syntax, […]

The post Insert into javascript array at a specific index appeared first on Justin Joyce.

]]>
There are two options when inserting into an array in javascript: slice() and splice().

Array.prototype.slice

Array.prototype.slice returns a copy of a portion of an array, like so:

const myArray = ["a", "b", "d", "e", "f"];

// Slice starting at [0], and take 2 elements
myArray.slice(0, 2) // ["a", "b"]

// if you don't pass a second argument,
// slice will go all the way to the end of the array
myarray.slice(2) // ["d", "e", "f"]

Let’s say we want to insert c where it belongs in this list, between b and d.

const originalArray = ["a", "b", "d", "e", "f"];

const newArray = [...myArray.slice(0, 2), "c", ...myArray.slice(2)];

// newArray looks good
console.log(newArray); // ["a", "b", "c", "d", "e", "f"]

// originalArray hasn't changed
console.log(originalArray); // ["a", "b", "d", "e", "f"]

The three dots ... in the above example are known as javascript spread syntax, and are frequently used for expanding arrays like this.

Array.prototype.splice

In the slice example, the original array remained unchanged; we created a new copy. Array.prototype.splice, however, will modify the original array in place.

const originalArray = ["a", "b", "d", "e", "f"];

// The 0 here means "don't delete any elements" (another use of splice)
originalArray.splice(2, 0, "c");

console.log(originalArray); // ["a", "b", "c", "d", "e", "f"];

Modifying arrays in place can be a dangerous operation. If you have an array which is imported into multiple project files and one of them calls .splice() on it, it’ll change the value everywhere. For that reason, I generally prefer to use slice for something like this; I like to keep my objects immutable.

The post Insert into javascript array at a specific index appeared first on Justin Joyce.

]]>
Calculate Date Difference in Javascript https://justinjoyce.dev/calculate-date-difference-in-javascript/ Thu, 19 Jan 2023 12:49:45 +0000 http://mdh.tqp.mybluehost.me/calculate-date-difference-in-javascript/ You have two main options: Let’s go through a quick example of each approach. Using date-fns to get date difference Above, I mentioned luxon, day.js, and date-fns. They’re all great packages, but I personally prefer date-fns due to its easily searchable documentation. date-fns has a ton of other functionality and the docs are very good […]

The post Calculate Date Difference in Javascript appeared first on Justin Joyce.

]]>
You have two main options:

  1. Use an npm package1 like luxon, day.js, or date-fns
  2. Convert each date to milliseconds, subtract, and multiply

Let’s go through a quick example of each approach.

Using date-fns to get date difference

Above, I mentioned luxon, day.js, and date-fns. They’re all great packages, but I personally prefer date-fns due to its easily searchable documentation.

const {
    differenceInDays,
    differenceInHours,
    differenceInMinutes,
} = "date-fns";

const twentyThree = new Date("2023/01/01");
const twentyTwo = new Date("2022/01/01");

differenceInDays(twentyThree, twentyTwo);
// 365

differenceInHours(twentyThree, twentyTwo);
// 8760

differenceInMinutes(twentyThree, twentyTwo);
// 525600

date-fns has a ton of other functionality and the docs are very good (and searchable!), I’d recommend using it.

Using pure javascript

This is a bit more convoluted, but doesn’t require any additional packages. It does, however, require a bit of knowledge of what Unix Time is. To plagiarize wikipedia:

Unix Time […] measures time by the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970, the beginning of the Unix epoch, less adjustments made due to leap seconds.

Now that you know that, let’s get into it:

const twentyThree = new Date("2023/01/01");
const twentyTwo = new Date("2022/01/01");

// Convert both dates to millisecond Unix time
// I know I said "seconds" above, but JS does it in MS ¯\_(ツ)_/¯
const twentyThreeMs = twentyThree.getTime();
const twentyTwoMs = twentyTwo.getTime();

// calculate the difference
const diffMs = twentyThreeMs - twentyTwoMs;

const msPerDay = 1000 * 60 * 60 * 24;
// 1000 ms per second
// 60 seconds per minute
// 60 minutes per hour
// 24 hours per day

const differenceInDays = diffMs / msPerDay;
// 365

const msPerHour = 1000 * 60 * 60;
const differenceInHours = diffMs / msPerHour;
// 8760

// Minutes
console.log(diffMs / 60000);
// 525600

Not too bad, even in plain JS. In larger projects though, there’s a good chance you’ll be doing other operations on dates, and a nice npm package like date-fns will definitely make your life easier.


Notes

  1. For years, moment.js was the be-all and end-all of javascript date manipulation. However, it’s now in maintenance mode, and moment’s maintainers themselves recommend the three alternatives posted above. ↩

Helpful Links

What is Epoch (Unix) Time? – wikipedia

Date-fns documentation

The post Calculate Date Difference in Javascript appeared first on Justin Joyce.

]]>
Convert between timezones in Javascript https://justinjoyce.dev/dates-and-timezones-in-javascript/ Sat, 17 Dec 2022 00:06:24 +0000 http://mdh.tqp.mybluehost.me/dates-and-timezones-in-javascript/ Javascript dates are frequently stored in UTC, or Coordinated Universal Time, specifically so we don’t have to store time-zone-adjusted dates. You’ll often see ISO-formatted date strings ending in Z like this: 2022-12-15T21:07:49.883Z. That Z means “Zulu”, and is just military jargon for “UTC”. Greenwich Mean Time (GMT) is also exactly the same: GMT === UTC […]

The post Convert between timezones in Javascript appeared first on Justin Joyce.

]]>
Javascript dates are frequently stored in UTC, or Coordinated Universal Time, specifically so we don’t have to store time-zone-adjusted dates. You’ll often see ISO-formatted date strings ending in Z like this: 2022-12-15T21:07:49.883Z. That Z means “Zulu”, and is just military jargon for “UTC”. Greenwich Mean Time (GMT) is also exactly the same: GMT === UTC === Zulu.

Option 1: Use date.toLocaleString

Lets change that UTC to something more useful, since most internet users are not on UTC:

// Take a date string
const dateString = "2022-12-15T21:07:49.883Z";

// Turn it into a Date object
const dateObject = new Date(dateString);
// Thu Dec 15 2022 16:07:49 GMT-0500 (Eastern Standard Time)
// My browser automatically adjusted the format to EST, my location

dateObject.toLocaleString('en-US', { timeZone: "Asia/Shanghai" });
// '12/16/2022, 5:07:49 AM'

dateObject.toLocaleString('en-US', { timeZone: "Asia/Kolkata" });
// '12/16/2022, 2:37:49 AM'

dateObject.toLocaleString('en-US', { timeZone: "America/Los_Angeles" });
// '12/15/2022, 1:07:49 PM'

// Using locales, you can also get the correct date format
// for the date's location if needed
dateObject.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })
// '16/12/2022, 2:37:49 am'

dateObject.toLocaleString('zh-cn', { timeZone: "Asia/Shanghai" });
// '2022/12/16 05:07:49'

Option 2: Use Intl.DateTimeFormat

If you’re going to do a lot of converting to a specific time zone or locale, you can also use the Intl.DateTimeFormat built-in:

// this californiaTime object will have a .format() method
// which operates on Date() objects
const californiaTime = new Intl.DateTimeFormat(
    "en-US",
    {
        timeZone: "America/Los_Angeles",
        timeStyle: "long",
        dateStyle: "short",
    }
);

const randomIsoTimes = [
    "2022-01-03T22:21:54Z",
    "2012-12-15T21:31:38Z",
	  "1999-06-01T04:04:28Z",
]

// Now pass each of these dates to our pre-built formatter
randomIsoTimes.map(timeString =>
	californiaTime.format(new Date(timeString))
)
/* 
	[
		  '1/3/22, 2:21:54 PM PST',
	    '12/15/12, 1:31:38 PM PST',
    	'5/31/99, 9:04:28 PM PDT',
	]
*/

Personally, I find the Intl package to be a bit much for most use cases and I usually use .toLocaleString(), but Intl does have a ton of options for customization. Intl is also very useful for reformatting numbers, particularly currencies, but that’ll be for another post.


Helpful Links

The post Convert between timezones in Javascript appeared first on Justin Joyce.

]]>