Destructuring JavaScript Arrays Object(ively)

Destructuring JavaScript Arrays Object(ively)

TL;DR

Since JavaScript arrays are basically objects (with special behavior for index properties), they are valid targets for object destructuring. Hence, making the following destructuring statements equivalent.

// Array to be destructured
const RGB = [255, 180, 151];

// Array Destructuring
const [red, green, blue] = RGB;

// Object Destructuring (equivalent)
const {0: red, 1: green, 2: blue} = RGB;

Using the object destructuring syntax makes for more flexible and complex destructuring of arrays and array-like objects, where it wouldn't be possible or reasonable otherwise to use array destructuring, due to limitations.

Continue reading to find out more…


Background

The syntax for destructuring objects was added to the ECMAScript Language Specification starting from ES2015 (popularly known as ES6). This syntax makes it possible to break down complex JavaScript values like objects into simpler parts that can be assigned to local variables.

The destructuring syntax comes in two basic flavors:

1. Array destructuring

// Array that will be destructured
const RGB = [255, 180];

// Array Destructuring
// Skip the first item
// Set a default value (51) for the third item (`blue`)
const [, green, blue = 51] = RGB;

console.log(green); // 180
console.log(blue); // 51

2. Object destructuring

// Object that will be destructured
const AUTHOR = {
  name: "Glad Chinda",
  lang: "JavaScript"
};

// Object Destructuring
// Declare a local variable (`language`) for `lang`
// Set a default value (16) for `age`
const {name, lang: language, age = 16} = AUTHOR;

console.log(name); // "Glad Chinda"
console.log(lang); // undefined
console.log(language); // "JavaScript"
console.log(age); // 16

However, it is possible to have a destructuring syntax that is a mix of both flavors, nested in a certain way.

In this post, we will focus on destructuring for arrays and other JavaScript iterables. If you are not already familiar with the destructuring syntax, you can check out ES6 Destructuring: The Complete Guide to learn more.


Array Destructuring

The array destructuring syntax proves useful for a number of applications. A very common application of array destructuring is in swapping variables.

Without the array destructuring syntax, swapping the values of two variables will always require a third temporary variable. With array destructuring, let’s just say that won’t be necessary.

// Variables to be swapped
let width = 1280;
let height = 720;

// METHOD 1
// Swapping Variables (without array destructuring)
// A temporary variable is required
let temp = width;

width = height;
height = temp;

// METHOD 2
// Swapping Variables (with array destructuring)
[width, height] = [height, width];

Another very common use of the array destructuring syntax is in combination with the rest parameter syntax for cloning arrays.

// Array to be cloned
const scores = [23, 27, 22, 41, 35];

// Clone the `scores` array
const [...scoresClone] = scores;

console.log(scoresClone); // [23, 27, 22, 41, 35]
console.log(scores === scoresClone); // false

Array destructuring isn’t limited to arrays alone (unlike the name implies), rather it can also be used with JavaScript iterables of all kinds such as strings, sets, array-like objects like arguments object, etc.

// Destructuring a String
const [firstChar, ...otherChars] = "Hello";

// Destructuring a Set
const [,, thirdItem] = new Set([1, 2, 3, 4, 5]);

console.log(firstChar); // "H"
console.log(otherChars); // ["e", "l", "l", "o"]
console.log(thirdItem); // 3


Limitations of Array Destructuring

Let’s say we have an array ITEMS of 100 items and we want to assign the value of the 3rd item in the array to a variable named thirdItem. Basically, that can be done as follows:

// METHOD 1 — Using Item Index
// The 3rd item will be at index 2
const thirdItem = ITEMS[2];

// METHOD 2 — Using Array Destructuring
// Simply skip the first two items
const [,, thirdItem] = ITEMS;

Now that was easy since we only needed the third item. What if we were interested in the last item instead? In that case, doing the assignment using the array destructuring syntax wouldn’t make any sense, because it literally means we have to skip the first 99 items(using commas) to get to the last item.

And that’s just for an array of 100 items. It’s even worse when the number of items in the array is not known beforehand. Getting the last item in the array will require knowing the length of the array — something like this:

// Accessing the last item in the ITEMS array
const lastItem = ITEMS[ITEMS.length — 1];

One might think for a moment here, that array destructuring can again be combined with the rest parameter syntax to solve this problem.

// Throws a SyntaxError
// Rest parameter element must always be the last element
const [...skippedItems, lastItem] = ITEMS;

The combination of array destructuring and rest parameter, as shown above, fails with a SyntaxError due to the limitations placed on the rest parameter element:

  1. You can only have one rest parameter element.
  2. The rest parameter element, whenever present, must be the last element.

Is there a different approach we can try?

Since fundamentally, JavaScript arrays are objects (with special behaviors), one would guess that they should be valid targets for object destructuring.


Object Destructuring to the Rescue

According to the ECMAScript Language Specification, an array object is an exotic object that gives special treatment to array index property keys. What that means is that each index in the array is a valid property key of the array.

Hence, the following destructuring statements are equivalent (for an array):

// Array to be destructured
const RGB = [255, 180, 151];

// Array Destructuring
const [red, green, blue] = RGB;

// Object Destructuring (equivalent)
const {0: red, 1: green, 2: blue} = RGB;

Coming back to our problem from before with this new knowledge, we can get the last item in the ITEMS array and assign it to the lastItem variable like so:

// Using object destructuring
// The last(100th) item will be at index 99
const { 99: lastItem } = ITEMS;

Pushing further, let’s say we want to access items in sparse positions of the ITEMS array — for example the first, third, middle (50th), and last items. While it might be impractical to achieve that using the array destructuring syntax, it is a piece of cake when using the object destructuring syntax.

// Using object destructuring
// ITEMS array contains 100 items
const {
  0: firstItem,
  2: thirdItem,
  49: middleItem,
  99: lastItem
} = ITEMS;

It is also important at this point to note that the order of index properties does not matter when using object destructuring.

// Using object destructuring
// Order of index properties does not matter
const {
  2: thirdItem,
  99: lastItem,
  49: middleItem,
  0: firstItem
} = ITEMS;


More with Object Destructuring

When using object destructuring for arrays, we are not limited to only the index properties of the array object — we can also access other enumerable named properties existing on the array such as length.

// Using object destructuring
// Get the first item and the length
const { 0: firstItem, length } = ITEMS;

Using the object destructuring syntax, it becomes possible to access computed properties. For example, we can get the first, middle, and last items of the ITEMS array using computed properties as follows:

// Using object destructuring
// Get the first, middle and last items
const {
  0: firstItem,
  [ITEMS.length — 1]: lastItem,
  [Math.floor(ITEMS.length / 2)]: middleItem
} = ITEMS;

We can modify the previous code snippet, introducing the length property of the array, like so:

// Using object destructuring
// Get the length and first, middle and last items
const {
  length,
  0: firstItem,
  [length — 1]: lastItem,
  [Math.floor(length / 2)]: middleItem
} = ITEMS;

And if we choose to assign the value of the length property to a local variable with a different name, we can do this:

// Using object destructuring
// Get the length and first, middle and last items
// The length is assigned to the `size` variable
const {
  length: size,
  0: firstItem,
  [size — 1]: lastItem,
  [Math.floor(size / 2)]: middleItem
} = ITEMS;


Going Beyond Arrays

The object destructuring syntax we’ve explored so far does not work for only JavaScript arrays. It can be used for strings and other kinds of array-like objects in JavaScript with special behavior for index properties — such as a function’s arguments object.

Object destructuring for string:

// String to be destructured
const STRING = "Hello World!";

// Object destructuring for string
const {length, [length — 1]: lastChar} = STRING;

console.log(length); // 12
console.log(lastChar); // "!"


📖 Further Reading

For a more in-depth understanding of the destructuring syntax in JavaScript, the following resources will prove very useful.

  1. ES6 Destructuring: The Complete Guide
  2. Destructuring assignment
  3. ES6 In Depth: Destructuring
  4. Destructuring assignment


Conclusion

Using array destructuring has potential limitations when trying to destructure values in sparse positions of an array or array-like object. For example, it can be very daunting to get the last item in a large array using array destructuring.

However, switching to object destructuring provides more flexibility to handle even more complex destructuring on arrays and array-like objects. You are not just limited to index properties when using object destructuring—named and computed properties can be destructured as well if they are enumerable.


Your Feedback

Thanks for making out time to go through this post.

  • Please remember to drop your feedback or questions in the comments.
  • If you found this post insightful, please go ahead and share with your friends, and also hit the Like button to help others find it easily.
  • You can follow me on Twitter (@gladchinda) to get notifications about more insightful content coming up soon.

Happy coding…