New ECMAScript Features to Help Get You Through Your Day
Programmers are always looking for new ways to make their lives easier, and I’m no different. That’s why I will occasionally find myself perusing the latest ECMAScript specification for features that may help me with my day-to-day. Today I’d like to draw some attention to some of the newest features that I believe will have a significant impact on the way we write code in JS.
The .at() method
The .at() method allows for the use of “negative indexing” of basic JS iterables (Array, String, TypedArray). This is a feature in other languages, like Python, and is something JS developers have been asking for for quite some time now.
Why doesn’t negative indexing an array work when using bracket notation? This is because the [ ] syntax is not exclusive to Arrays and Strings. It applies to all objects. Referencing arr[-1] yields undefined, because you are really trying to reference the property of an object with a key of “-1”.
Getting the last item in an array using arr[arr.length — 1]
const arr = [1, 2, false, 'foo']; const lastItem = arr[arr.length -1] console.log(lastItem) // Outputs: 'foo' view raw
Having to name the indexable class twice has always felt a bit clunky to me. In addition to being overly wordy, this method does not lend itself to indexables returned by a function.
function returnArray() { return [1, 2, false, 'foo']; } const tempArr = returnArray(); console.log(tempArr[tempArr.length -1]; // Outputs: 'foo' view raw
Using .slice
Negative indexing is supported by the .slice method (as well as .splice) and functions as desired.
const arr = [1, 2, false, 'foo']; const lastItem = arr.slice(-1)[0]; console.log(lastItem); // Outputs: 'foo'
Using the .slice method also gets rid of the need to store an array returned from a function in a variable before referencing it.
function returnArray() { return [1, 2, false, 'foo']; }; console.log(returnArray().slice(-1)[0]); // Outputs: 'foo'
What to note here is that the return value of .slice is itself an array, and so we need to append the [0]. While this syntax is more flexible than the first, I still believe it is not the most readable.
Let’s see how this would be achieved with the .at() method.
const arr = [1, 2, false, 'foo']; // last item in array console.log(arr.at(-1)); // Outputs: 'foo' // second-to-last item console.log(arr.at(-2)); // Outputs: false function returnArray() { return [3, 4, true, 'bar']; }; // works with anonymous values console.log(returnArray().at(-1)); // Outputs: 'bar'
Terse. Flexible. Readable.
Object.hasOwn()
The new Object.hasOwn() method is meant to be a replacement for Object.hasOwnProperty(). It is used to check if a property exists on a given object.
const obj = { foo: 'bar' }; console.log(Object.hasOwn(obj, 'foo')); // Outputs: true
The main difference between the two methods is that Object.hasOwn() only checks for properties owned by a given object, and ignores properties inherited from Object.prototype. This is useful because methods on Object.prototype may not always be available.
Such is the case for objects created with Object.create(null)
// methods on Object.prototype are not available here const object = Object.create(null); console.log(object.entries()); // Uncaught TypeError: object.entries is not a function
The added benefit of this is that it negates the need for third-party implementations like lodash.has.
Numeric Separators
I am a big proponent of readability, so the addition of numeric separators is a feature that’s had me pretty excited. Numeric separators allow for the use of an _ to create a grouping of integers making it easier for developers to quickly decipher large numbers.
const largeNum = 1000000000; const readableLargeNum = 1_000_000_000; // Same number as above
Logical Assignment Operators
The new ECMAScript specification introduces a set of logical assignment operators similar to ones found in other languages like Ruby, and can save you a few lines of code.
Logical OR Assignment
Assigns when the value to the left of the operator is falsey.
// before let x = undefined; if (!x) { x = 5; } console.log(x); // Outputs: 5 // after let y = undefined; y ||= 5; console.log(y); // Outputs: 5
Logical AND Assignment
Assigns when the value to the left of the operator is truthy.
// before let x = 5; if (x) { x = 6 } console.log(x); // Outputs: 6 // after let y = 5; y &&= 6; console.log(y); // Outputs: 6
Logical Nullish Assignment
Assigns when the value to the left of the operator is nullish (null or undefined).
let x = null; x ??= 5; console.log(x); // Outputs: 5
Resources
All of the features mentioned here have reached Stage 4, and are supported by most modern browsers. Here are some links to the documentation in case you would like to learn more.