Three new to me JavaScript features
For September the learning focus was JavaScript. Yeah, it was that vague. When getting started, I did the typical Googling and Redditing to get a pulse on what is popular. This was followed by skimming a few books and tutorials, ultimately deciding this was going to be the time I went through javascript.info. Although I had bookmarked the tutorial years ago, I never really took any time to go through it. I managed to finish the first four of fourteen sections on the JavaScript language, and would hope to finish the full guide in the not to distant future.
Looking back through my notes, I’ve decided to share some comments on three features of the language that were new to me as I went through the site.
BigInt
While performing math calculations is one of the most foundational things that computers do, there are quite a few cases where the numbers don’t quite work out as expected.
A personal experience with this that has always stuck with me happened during my undergraduate studies. I remember very few specific lectures, or assignments from that time, but this one had a big impact. It took place in my modern physics course, Introductory Relativity and Quantum Physics. As a class we were given feedback that most of us had incorrectly calculated one of our homework problems. When dealing with subatomic particles, the numbers involved can get pretty tiny, but even then our fancy TI-89 calculators usually had no problem with them… most of the time. For this problem, the operations were straight forward enough that when the professor told us of our poor performance, one of the students quickly re-ran the numbers on his calculator in an attempt to prove that we were right. Teachers do make mistakes, but not this time. He proceeded to run through the math by hand on the board demonstrating the correct solution. This had a big impact on my ability to blindly trust computers. Often even though it appears they are doing what we want, there are sometime unforeseen pitfalls.
In JavaScript, one of these historic pitfalls has been the safe handling of large numbers.
Simply put, integers outside of the safe range of ±(2^53-1) may lead to inaccurate calculations. With very very large numbers, the number primitive stops trying and instead returns Infinity
.
The solution to this is BigInt.
Syntactically, BigInt numbers are simply written with an “n” suffix.
So, typeof(1n)
is ‘bigint’ and typeof(1)
is ’number’
2 ** 10000
returns ‘Infinity’
2n ** 10000n
returns an enormous number
Any mixing of bigint and number primitives returns a TypeError
While reading up on this, I found a number of resources useful, but I found the bigint TC-39 proposal to be the most interesting and comprehensive.
The feature started making it’s way into the various JavaScript implementations in 2018, soon after the proposal reached stage 3.
Will I ever use BigInt? At this point, I don’t have a use case. When I first encountered the concept I figured this was going to be the future of all numbers. Unfortunately, for reasons explained in the proposal, BigInt numbers are discouraged unless it is clear that truly large integers are required. Whomp whomp.
Still, it’s interesting to know the feature is there.
Should I have fallen into this detour so early in the javascript.info tutorial? No, but given BigInt is one of the 7 primitives of the language, it’s will likely always be mentioned in many introductions to the language. For someone taking a slow approach to exploring the language, in the end this feature felt like a trap. A fun detour, but ultimately not very useful.
Back to my personal experience with inaccurate computer numbers, Wolfram Alpha amusingly also confirmed the professors answer. If the problem were harder, we likely would have used that to sanity check our answers. We got a lot of mileage from that site during undergrad.
Deep copy with structuredClone()
A common error that I’ve made in the past and even caught in a pull request from an experienced developer earlier this year occurs when attempting make a copy of an object. Unlike with other primitives such as numbers and strings, when a new variable is assigned to an existing object, nothing is actually duplicated. Instead the new variable only acts as a new pointer to the existing object. Changing the properties of one will affect the other.
To copy the contents of an object we have a couple different conceptual approaches, shallow copy or deep copy.
Put simply… Shallow copy - Copy all the top level properties of the object Deep copy - Copy all the properties of an object including all referenced objects. The big difference here is the cloning of the referenced objects. A shallow copy will point to the same shared “other objects” while a deep copy will avoid these shared properties.
In JavaScript, these days the most common way to copy objects usually involves the spread operator {...obj}
, but this only performs a shallow copy. If a deep copy is required, until quite recently there was no simple solution built into the language.
Starting in late 2021, despite not being accepted into the ECMA standard, browsers began to introduce the structuredClone() method to handle this, making native deep cloning possible.
Having used deepcopy()
on multiple occasions in Python, I suspect this method will become increasingly common with JavaScript, especially as it gains popularity outside of the browser.
Option Chaining
Although I haven’t been writing lots of JavaScript recently, I want to force myself to use of this feature sometime in the near future. The syntax is so simple.
The problem, which I’ve encountered many times, occurs when trying to access nested object properties. If the presence of a parent object is not guaranteed, such as when accessing nested JSON from an API call, this usually calls for additional conditionals to test if the parent exists before referencing the children. Option chaining makes this simple. To implement it, question mark can be added before the dot when accessing the property of an object that may not exist. This than returns undefined
if the optional parent is missing instead of a TypeError. If that paragraph was confusing hopefully an example should make it clearer.
So, for example, when given a object
let things = {
'food': {
'good': ["milk", "carrots", "cheese"],
'bad': ["beets", "cauliflower rice"],
}
};
If I try to access
things.food.good
I will get
["milk", "carrots", "cheese"]
So far so good?
BUT, if I try to access
things.clothes.good
I will get the exception
Uncaught TypeError: Cannot read property 'good' of undefined
If I instead use the new conditional operator
things.clothes?.good
I will get a safer
undefined
And all it took was a ?
. 😃
Like many new features of the language, this comes with cautions and warnings about great power, great responsibility, blah blah blah. I like it. I want to use it.
Also, in this case, new means the feature first appeared in browsers in the spring of 2020
Can I use option chaining?
TC39 option chaining proposal, stage 4
End of month thoughts
There are a LOT of tangents the javascript.info tutorial led me onto. Trying to read these types of resources thoroughly inevitably revealed a few gems, more than I covered here, but it did not always feel like the best return for my time. At times while going through the guide, it felt a too light on writing code. The exercises were good, but sometimes left me feeling like I wasn’t improving my intuition for the things I was reading. So, as my time looking at JS in September continued, I found myself switching gears and practicing some leetcode problems instead. If nothing else, solving puzzles feels much more satisfying than reading books.
Future paths of study
Building on my fundamental skills, I’ll probably continue with the javascript.info tutorial in the future. More leetcode is almost a given.
There are plenty of other well known books and resources out there, but the one jumped out at me was “The Joy of JavaScript (2021)”. I only stumbled into this one because my local library had a copy. Didn’t get a chance to read it, but covers some really appealing topics.
Bonus item left out
I had originally also wanted to talk about constructor functions because they started to help me understand a little of why the symbol
primitive exists, but breaking them down would have taken longer than I wanted. Instead, it’s time to switch gears completely away from JavaScript into something all together fresh and new.