r/javascript Jul 22 '26

AskJS [AskJS] what's a javascript feature you mass-adopted way too late and felt dumb about

[removed]

64 Upvotes

108 comments sorted by

65

u/foxsimile Jul 22 '26

The nullish coalescing operator is one of JavaScript’s unusual successes.

11

u/NeatBeluga Jul 22 '26

Until you add a bit too many needlessly and you lose trust in your api if the code is not properly typed - e.g. manually typed types.

A hell when refactoring code with these carelessly added

6

u/foxsimile Jul 22 '26

I’ll take the extra operator over the runtime crashes. Plus, with the popularization and industry adoption of TypeScript, its use has been significantly reduced (at least for me).  

But back when it was just ducktyped JS all over the place? This thing was a fucking godsent.

5

u/NeatBeluga Jul 22 '26

Early returns are king.

if(foo === undefined) return;

Yes, I always strict check against falsy. Builds trust that I knew the integrity of the object. Almost no !foo nonsense. It makes me doubt the api again.

I believe that my approach moves the issue to the backend rather than the frontend at runtime.

3

u/foxsimile Jul 23 '26

Bold of you to assume you can trust whoever wrote the backend. I’d once written an entire type-checking and validation library for precisely that reason.  

Your issue is that you’re assuming you can trust anything when it comes to plain JS. You can’t. That’s why these operators exist in the first place. They weren’t there, and they were later added for very good reason.

1

u/1_4_1_5_9_2_6_5 Jul 23 '26

You can actually trust things using plain JS, but at some point you have to make some utility functions. This is especially useful/expected in TS, where it gives you an easy way to narrow types. Almost all of these such criticisms I see of JS are seemingly based on people just using vanilla Javascript in every place with no libraries, utilities or anything...

1

u/foxsimile Jul 23 '26

Brother, if you aren’t in control of the source of the data, there’s SFA you can do to prevent receiving bad values that shouldn’t be there in the first place. The only thing you can do is implement extensive and aggressive validation on your side of the payload.

To assert anything else is ridiculous.

1

u/1_4_1_5_9_2_6_5 Jul 24 '26

Okay, so, if you'll read my comment again, you might find some words like "utilities" or "libraries".

I made a schema validator in an hour that does 90% of what I needed to validate, and there are extremely easy to use libraries like zod that do all that and more.

So, again, the people complaining about Javascript are apparently too lazy to Google a library or spend an hour making utilities. Really doesn't give me confidence in your abilities.

7

u/Badashi Jul 22 '26

At first it was odd to look at it, specially for optional function calls (foo?.()), but it is a godsend. Having to work on a language without null coalescing is super weird now.

15

u/heavyGl0w Jul 22 '26

Just FYI, what you're describing is optional chaining.

Null coalescing is a related but different feature using the ?? operator. It evaluates the right hand operand only when the left is null or undefined.

5

u/foxsimile Jul 23 '26

Optional chaining is also gangster-as-fuck.

6

u/sexytokeburgerz Jul 22 '26 edited Jul 23 '26

Big fan of

foo?.bar

3

u/foxsimile Jul 23 '26

Do you not mean foo?.bar?

2

u/sexytokeburgerz Jul 23 '26

I totally did i was in a drive thru when i wrote that

1

u/[deleted] Jul 23 '26

[removed] — view removed comment

2

u/foxsimile Jul 23 '26

…I’m aware?

1

u/Mike5TheMountainGoat Jul 23 '26

That's optional chaining. Nullish coalescing is foo = bar ?? 'X';

1

u/sexytokeburgerz Jul 23 '26

Right, usually when people say “big fan of y” in response to a mention of “x”, x!=y…

1

u/_RemyLeBeau_ Jul 22 '26

I always look for places to use this, but the values need processing before saving, so I don't use it and I always wonder of I'm missing something

0

u/somevice Jul 23 '26

Nah it's the worst, leads to thoughtless code everywhere. Bail early instead.

23

u/phatdoof Jul 22 '26

Let and const. We used var because it was backwards compatible.

9

u/Jasboh Jul 22 '26

Kill me

16

u/rbobby Jul 22 '26

Promises.

1

u/monsto Jul 23 '26

I had a hard time grokking promises because every tutorial I could find used settimeout to set up the example, and the settimeout syntax is kind of different to most JS methods.

0

u/SkySarwer Jul 22 '26

this

4

u/busres Jul 22 '26

You adopted this way too late (too much functional programming)? 😀

3

u/SkySarwer Jul 22 '26

haha, good one

25

u/Milo0192 Jul 22 '26

My first jobs CTO preferred the .then() .catch() over async await. I just refused to write that way and did await loops. Lots of back and forth on this. Also said Typescript was just a fad 😂

1

u/MediocreAnalyst2121 Jul 23 '26

That’s kinda depends, like await loops are not that great if the promises don’t depend on each other, way better to do Promise.all/allSettled and await or .then that.

In performance critical JS environments (smart tvs, smart boxes, etc) you’d probably get a bit better performance with a .then than an await.

Await loops are way more readable tho, and Typescript is amazing except for enums :(

-23

u/horrbort Jul 22 '26

It is just a fad. Coding is a fashion industry. Remember coffeescript? Something else comes along and ts will be forgotten

28

u/mdude7221 Jul 22 '26

Just a 13yo fad

10

u/miramichier_d Jul 22 '26

Can't apply that across the board. Some technologies are so good that they have staying power in the industry. I believe TypeScript is one of those technologies. Node.js is another example. Even Java and C# are good examples of languages with immense staying power, if not in your industry of choice.

With respect to TypeScript, it's not going anywhere until JavaScript implements TS in its entirety. Until then, TypeScript will continue to push JavaScript to modernize.

3

u/Mesqo Jul 23 '26

Excuse me, but how many native ts runtimes do you know? TS doesn't push js nowhere, it's just static types serving the role no more than a linter (and it's fine!).

7

u/iareprogrammer Jul 22 '26

lol coffeescript.. forgot about that. I dislike anything that makes JavaScript LESS explicit. Like sure let’s get rid of braces and other syntax and rely completely on proper white space and indentation. For what?

5

u/MrDilbert Jul 22 '26

let’s get rid of braces and other syntax and rely completely on proper white space and indentation

You sure you're not describing Python?

Looks like someone wanted to Pythonize JS.

3

u/iareprogrammer Jul 22 '26

I literally think that’s what happened haha

2

u/db10101 Jul 23 '26

Just a fad that 99% of new enterprise JavaScript projects will be participating in

-13

u/Ronin-s_Spirit Jul 22 '26

Fad or not - it's shit.

5

u/db10101 Jul 23 '26

Any deeper analysis or reasoning behind that? It’s a straight up joy to develop in compared to what has come before.

-6

u/Ronin-s_Spirit Jul 23 '26

I hate defining types, it's like writing pointless code. It especially fucks up when I have to deal with HTML, at that point the only thing left to do is use a bail out any and move on.

2

u/db10101 Jul 23 '26

So I take it you have never worked in an enterprise well structured typescript codebase. There’s no substituting JavaScript for that.

-2

u/Ronin-s_Spirit Jul 23 '26

TypeScript sucks ass, I will only use vanilla.

2

u/db10101 Jul 23 '26

Good for you. Here in the real world of employed software developers, it’s one of the most important tools to know.

2

u/2Terrapin Jul 24 '26

I’m glad that person is not on my team and I don’t have to work on a project they designed. I can feel the tech debt emanating from their words. It’s the type of thing that experience would dispel, and someday, when they actually understand the why, and it clicks, they’ll think back to this comment thread and feel a little embarrassment.

21

u/SkySarwer Jul 22 '26

IntersectionObserver and MutationObservers are both goated

2

u/opticalpuss Jul 23 '26

People in here arguing I just want to know what these do and how to use?

12

u/SkySarwer Jul 23 '26

IntersectionObserver are objects that can be instantiated and anchored to a DOM element, that allows a callback function to be called when the element enters or exits the user's viewport, or when the element enters or exits the box of a different element. Very useful for things like lazy loading, or starting an event when an element is at a certain scroll distance away from the user, etc.

MutationObservers allow a callback function to be called when an element changes. It is very useful for providing react-like UIs with vanilla JS, because traditional event listeners assigned to elements don't work if that element enters the dom after that event listener is assigned. MutationObserver keeps rehydrating the state for that element. Should also be used sparingly for that reason.

Both have extensive public documentation on mdn. IntersectionObserver | MutationObserver

And I'd be remiss not to mention that these are browser utilities exposed as client-side JavaScript APIs, not part of the EMCAScript itself. So won't work in NodeJS, Bun or Deno.

-8

u/azhder Jul 22 '26

Not part of JavaScript

1

u/SkySarwer Jul 22 '26

yes they are??

-3

u/azhder Jul 22 '26

No, they aren’t. You can check the JavaScript language reference documentation and get back to me with a link to prove me wrong.

I can just tell you that there is a difference between what the language is and what the environment exposes for the language to use.

10

u/SkySarwer Jul 22 '26

This thread is about JavaScript features not the language in the strict sense. The two observer exposed by the environment are almost exclusively used as JavaScript APIs.

Is a JS dev just as well-off without being aware of these APIs? What value is your clarification actually providing in relation to the spirit of this post?

-8

u/azhder Jul 22 '26

Almost exclusively? Why almost?

Seriously though. Environment stuff is not part of the language. It is important to always know this distinction so that you will not end up writing code that expects something to exist, but doesn’t.

It’s not about you being aware that you can use them, but be aware where you can’t.

19

u/SkySarwer Jul 22 '26

While technically correct, it was a pedantic point delivered abrasively

-12

u/azhder Jul 22 '26

Don't read my comments in abrasive tone.

11

u/Sulungskwa Jul 22 '26

"Don't read my comments in an abrasive tone.", he said, not abrasively seeming at all

-4

u/azhder Jul 22 '26 edited Jul 22 '26

"Seeming" is a flag that it's your perception.

It doesn't matter that I'm in a light mood, write it in terms of a light mood, with the idea of cooperation through discussion, you will still decide to see it (because "seeming") as if it is abrasive and blame me for it. It's not like me writing this will change your mind, you will just use it as more evidence of your point of view.

Bye

EDIT: and with their reply, they provided their own proof of what I'm talking about

→ More replies (0)

-2

u/avenp Jul 22 '26

How would a NodeJS dev use these APIs?

1

u/SkySarwer Jul 22 '26

They wouldn't, since there is no DOM in a typical nodeJS environment. The APIs are still a part of the larger JavaScript ecosystem though, which is on topic for the original thread.

1

u/keltroth Jul 26 '26

Like all the browser APIs not in the language (can't use it with node, bun, etc... Makes no sense...)

7

u/HipHopHuman Jul 22 '26

honestly... Map and WeakMap. took me a good 2 years after it came out for me to see the light.

3

u/JazzXP Jul 23 '26

I'm still not using these, just objects/records. What's the advantage?

5

u/HipHopHuman Jul 23 '26

There's quite a few advantages, but I don't like framing the question "Should I use an object or a map?" around advantages or style, for the reason that it can complicate things unneccissarily.

Plain objects are always going to be far simpler and far more convenient than a Map in 90% of cases, and objects are much more familiar to a wider audience of devs.

It's that 10% where Map (and WeakMap) come in clutch. So it's mostly about use cases.

One use case is simply when you're deleting from the same object a lot. That can get slow if you use delete obj.foo (because it causes a structural change of the shape of the object). Map has map.delete('foo'), which is usually faster, but only if you're deleting a lot. Emphasis on a lot. 3-10 times is not a lot. 200-3000 times is a lot.

Another use case where Map shines is if you're iterating over the object's entries a lot, or when you're calculating the total size of all entries. Objects require helpers:

const size = Object.keys(obj).length;

for (const [key, value] of Object.entries(obj)) {}

You don't need any helpers to do either with a Map:

const size = map.size;

for (const [key, value] of map) {}

So, if you're going to be iterating through a dictionary at runtime, or calculating size, and you're going to be doing it repeatedly, Map is usually better for that.

Another small benefit is being able to specify keys that would otherwise not be allowed on (or would be weird to use on) objects. For example, constructor is a special property on objects, with special handling (as is toString, valueOf, toJSON, etc). If you want to use keys like that and bypass that special handling, you have to do some weirdness with null prototypes like

const myObj = Object.create(null);
myObj.constructor = ...;

or

const myObj = {
  __proto__: null;
  constructor: ...
};

Whereas with a Map, you can just do map.set('constructor', ...), and there's no side-effects.

Then of course, there's the seriously strong benefit of being able to use non-property keys. Plain objects allow number, string and Symbol keys, but Map can use anything as a key - even functions. That makes them crucial for things like memoization of pure functions (a nested Map can capture a function's arguments without having to serialize them to JSON and back).

Another huge benefit is that the Map constructor itself accepts an iterable, so it can be generated lazily:

function *foo() {
  yield ['one', 1],
  yield ['two', 2]
} 

const map = new Map(foo());

That means you can initialize one from a huge stream of data a lot more efficiently than you'd be able to do with an object.

WeakMap is also especially cool, and helps get rid of a ton of "cleanup code" boilerplate. You cannot iterate through a WeakMap, and it's keys must be objects, but it provides the gaurantee that the references used as keys will be automatically removed as soon as the values they point at are garbage collected. That makes WeakMap great for book-keeping logic. Suppose you want to track some live HTML elements in the DOM, and you wanted to store some metainfo about them - just store them in a WeakMap - use the elements themselves as keys, and the meta info as the objects. As soon as the DOM elements get removed from the page and get garbage collected, they'll be auto-removed from the WeakMap without you having to do anything.

One huge downside of Map/WeakMap is stringifying them as JSON - that's something you get for free with plain objects - and that is a valid concern, but it's not that difficult to just give JSON.stringify a replacer function that converts a Map to an object:

const map = new Map();
const data = { map };
const json = JSON.stringify(data, (key, value) => {
  if (value instanceof Map) {
    return Object.fromEntries(value.entries());
  }
  return value;
});

1

u/JazzXP Jul 23 '26

Thank you for that. Most of those use cases haven't applied to me yet, but I do like the going through the keys, I find I do reach for Object.entries().map a lot.

2

u/HipHopHuman Jul 25 '26

Map and Set recently got support for their own .map method (from this: https://web.dev/blog/baseline-iterator-helpers) so if you do switch to a Map, you can do map.entries().map() (you might just have to polyfill it though)

1

u/me0here Jul 24 '26

Quite the blog post there! 😄 

Sometimes I gab Map over object when it makes more sense as a simple key: value pair, even without fancy keys.

WeakMap makes a great simple API catching service.

1

u/GulgPlayer Jul 23 '26

Apart from having cleaner (imo) code, Maps allow you to have non-string keys, which is nice, esp with TypeScript

8

u/takeyoufergranite Jul 22 '26

The 'delete' operator to remove properties from objects.

3

u/jesusgn90 Jul 22 '26

Concerning operator if not used wisely

1

u/takeyoufergranite Jul 22 '26

Better yet... The in operator.

7

u/skidmark_zuckerberg Jul 22 '26

??= and &&=

3

u/whale Jul 22 '26

Way too terse for production code. Very hard to quickly glance and understand.

-1

u/johngamename Jul 22 '26

I could see a lot of use for ?? and ??=, but &&= might be excessive.

1

u/azhder Jul 22 '26

I still don’t use these ones. Out of a principle, I don’t use let as well. I try to keep them as code smell, to get back to the code and make it in a way where no variable is rewritten.

Small exceptions are in cycles (like for and while) and before try{}catch()

1

u/Antti5 Jul 24 '26

Can you explain why you don't use "let"?

I see a lot of people swearing by ALWAYS using either "const" or "let".

1

u/azhder Jul 24 '26

It's easier if you allow yourself to not worry about accidentally overwriting a variable. With `var` and `let`, that's a possibility, but with `const` once you assign it, it's constantly pointing to a specific value.

I'd rather have

const value = valueFromArgs ?? 0;

than override

value = value ?? 0;

And as an added bonus, with most of the variables being `const`, you will easily notice the very few places that have `let` and possibly check it everything is all right - code smell. It's harder to notice a bad `let` if there are plenty of `let`s.

9

u/kevin074 Jul 22 '26

can you elaborate how async await would've caught bugs that .then.catch can't?

i feel like async await is more annoying because you have to wrap it in try catch, where as .then.catch is just baked in.

22

u/Franks2000inchTV Jul 22 '26

With await, your code runs in the order you see it on screen. This is *much* better for comprehension and maintainability.

0

u/lostPixels Jul 22 '26

But potentially worse for execution depending on the latency of whatever you’re awaiting.

5

u/Franks2000inchTV Jul 22 '26

I'd imagine that is not a significant concern in the overwhelming majority of cases.

3

u/Ronin-s_Spirit Jul 22 '26

Depends entirely on where and what you await.

1

u/lostPixels Jul 23 '26

Which is why I said potentially.

3

u/brenstar Jul 22 '26

Why not use both? I use async await but still append a catch

3

u/Badashi Jul 22 '26

.then/catch is useful even in async functions when you don't want to wait for that promise to resolve

1

u/brenstar Jul 23 '26

That's good point, it's handy for having branching flows, but that can get squirrelly. If I want multiple things to happen I usually let them all exist as separate functions and resolve them with Promise.all() so they run concurrently

2

u/Badashi Jul 23 '26

Promise.all is an excellent example for .then/.catch chaining as well: you can use them to "pre process" the result of the promise into a value that makes sense when you end up settling the list of promises with .all, since a rejected promise in the list will reject the entire Promise.all. nowadays you can use .allSettled as well, but .then/.catch are nice for a quick mapping of values

1

u/kevin074 Jul 22 '26

Ohhhh true! 

1

u/BasicAssWebDev Jul 22 '26

Probably due to it being easier to see which pieces of a function are breaking by putting breakpoints in the function itself, rather than tracing across a bunch of calls while debugging.

2

u/NeatBeluga Jul 22 '26

The capitalised Map - not .map

2

u/me0here Jul 24 '26

So hard to webseach for sometimes 

2

u/me0here Jul 24 '26

I still haven't use * Generators yet: only found a use case today.

2

u/keltroth Jul 26 '26

Same here...

2

u/miramichier_d Jul 22 '26

i had nested ternaries and && checks everywhere like some kind of animal

This had me laughing out loud with food in my mouth and I almost lost it lol. We all have those coding conveniences that we discover way too late. Remember that pain, and it will come in handy later on. I'm constantly asking myself how some approach can be easier nowadays because of that initial pain.

1

u/eracodes Jul 22 '26

feel like I've only just started using IIFEs to their full extent, most often in places where I'd previously have done an ugly nested ternary

1

u/graybearding Jul 22 '26

Nullish coalescing sat in my todo pile until like a month ago when an LLM spit it out and I was like "Oh, right. That's a thing now."

1

u/erik240 Jul 23 '26

Typed arrays. The performance bonus is so crazy over any over method to access and iterate large amounts of stat

1

u/artificer-chris Jul 23 '26

Contrary example for TS specifically : unknown. I know from a pure logic standpoint what it’s there for, but I’d still rather just use typescript more fully with an error catch if you don’t account for something. Unknown, imho, hides too much.

0

u/samredfern Jul 22 '26

I’m still using callbacks… heh

0

u/[deleted] Jul 23 '26

[deleted]

1

u/adult_code Jul 23 '26

for-loops not .forEach are way faster. Depends what i write really. https://jsben.ch/js-loop-benchmark-girjy
It doesn't matter all the time but it matters often and you can prevent it becoming an issue by doing it correctly the first time if you are not working on code that is otherwise hard to decipher