Hacker News new | past | comments | ask | show | jobs | submit login
Two Features of JavaScript that you might not know (monkwhocode.com)
59 points by illuminated on Aug 6, 2020 | hide | past | favorite | 65 comments

I find the linked post about two new features in Node.js 14[0] much more interesting:

> Optional Chaining operator (?.)

> Nullish Coalescing operator (??)

Esp chaining can have a huge impact on readability.

[0]: https://www.monkwhocode.com/2020/05/nodejs-v14-2-things-to-k...

Optional chaining is also now supported in JS itself, with growing browser support: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Well now I feel stupid. I was irritated just yesterday at not having this feature available in JavaScript. I should have done a search. Looks like there's a babel plugin too: https://babeljs.io/docs/en/next/babel-plugin-proposal-option...

Not just in node.js but browsers too

Basic examples for null coalescing here https://byexample.xyz/javascript/ECMAScript2020/nullCoalesci...

This has been in Clojurescript since its inception back in 2011 or so, and the two new operators are handled by the same function:

  (get-in obj [key1 “key 2” (make-key obj 3) 4] “not-found”)
There is also a simpler version for single-level access with (get obj key not-found).

“not-found” can be a value or a function or a function evaluation, and the keys can be of any type, including nested maps or, if you wanna get really wild, functions.

Someday I’ll get to use this professionally instead of transpiling piles of NPM dependencies into something IE11 can work with...

Replying to my own comment to keep this properly namespaced:

Both of the new additions to JS specified in the article can be sort of done in cljs, though each one will be a function. This already fits with the existing paradigm; there are no operators in Clojure, only functions. “2 + 3” in JS is already “(+ 2 3)” in CLJS.

The Math.pow() vs “two stars operator” is kinda pointless: it can be reduced to (pow x y) with a require statement. Is that really used often enough to warrant new syntax?

Here’s how big numbers can be separated by space though. It does not handle overflows; I don’t think the JS version does either:

  (defn bignum [& xs] (js/parseInt (apply str xs)))
  (bignum 123 456 789)
  ;; yields 123456789 as a JS int
There’s an efficiency argument to be made here, in that a JS parser can do this with less overhead. But if you have that many unreadable big numbers written in your codebase, I think you have bigger problems.

I keep thinking that the optional chaining operator would also work for functions e.g. this.myOptionalfunction?('hello') were I would expect it would only get called when it's defined. But that's not possible, I think they missed a nice addition.

Oh looks like the operator is actually '?.' instead of just '?' so guess this.myOptionalFunction?.() could work but that looks really confusing in my eyes.

It has to be '?.(...)' not '?(...)', because '?(...)' is already part of valid syntax. For example "this.myOptionalfunction?('hello'):('goodbye')".

I am trying to think of a scenario where this makes sense, but I'm struggling. When do you want to call a function that might exist, and if so, not care about if it exists or not? (Since null or undefined returned from the function call can't be distinguished from the non-presence of the function)

Getting data from third party parsing as json. If method exists log and add person/item to data object

I was thinking to replace things like if(myFunction) { myFunction() }

And JavaScript slowly becomes typescript. Hooray!

I'm honestly hoping to see someone respond to you with why that would be a bad thing. Given my experience with TypeScript and how it makes my life easier, I can't see why anyone would have issue with it, but I know it must exist.

TypeScript is following JavaScript, not the other way around. Generally, ECMAScript proposals get added to TypeScript when they hit stage 3. Optional chaining and nullish coalescing were added to V8/Chrome and TypeScript around the same time.

Yes, TypeScript adds features from the ECMAScript standard. Sometimes JS implementations add them around the same time TypeScript adds them. But sometimes TS adds them much earlier. Having been using TS, it surprised me in this article that nodejs didn't add numeric separators until recently. I had to check MDN to make sure it was right. TS, with or without Babel, keeps me from having to know what features are supported where. I used to frequently check MDN and caniuse.com out of necessity. Now I check infrequently out of curiosity.

Oh I've been using this on TS without knowing it had a name. TIL

This has been in other languages (C#, Java) for ages.

Good for them!

Why in the world would you put a near full-page sized ad at the top of the article? I seriously thought that the site had been hijacked at first

I had the same thought... but then I realized they managed to share two very minor factoids about Javascript and reach front-page HN with it - so kudos to them for milking us for CPMs. :)

Don't you use an adblocker?

I've used this successfully for years.


While not your traditional ad blocker done via browser extension, it does the job quite well and blocks the requests at the OS level.

I'm not the author or maintainer, just a very happy user.

I use brave browser

I avoid using one on smaller sites so I can support content creators

I prefer to support them by sending actual money. I value my privacy and the loading speed of a website.

Did you send money for the article you just read?

If not maybe they need ads. So many people say they would rather pay directly but few do when given the chance.

Not this specific article, but I do pay to read content.

You don't need so many paying readers to get more money than ads. I also think that people should stop putting ads on their website when the gains are so little.

If writing is your job, write for a proper good media.

Remember when Google ads were two lines of text and a blue link?


A few more items added to the kitchen sink that is JavaScript.

JavaScript's multi-paradigm approach is one of its strengths, but, in my opinion, a weakness at the same time.

It allows people to write JavaScript following whatever approach suits them, which is fine for individual developers and small teams, but expand beyond that and it becomes a big ask for every developer to be up to speed with every feature JavaScript supports.

I use and teach JavaScript/TypeScript every day, and its possible to be very productive with it, but I prefer the approaches of Go and Clojure better. Limited languages that support a single paradigm, and support it well.

One of the goofiest things about JavaScript is how some of its most important and basic features and properties—say, prototypal inheritance and functions-are-objects—fall in the "you should probably never use these in any way that actually leverages their notable capabilities in JS, and if you think you need to, think again, and please... don't" category.

The result is that practically no-one wants to write in whatever a "JS native" paradigm might look like. Everyone wants to write it like C, or like Java, or like OCaml, or whatever. Mind, I don't think it's a bad thing people avoid writing "JS native" style, because I certainly don't want to be handed a codebase in which anyone's done anything remotely interesting with prototypal inheritance—it's just something I find interesting about the community of such a popular language.

This. Though pretentious "experts" push it as "a must know for senior JS developers". Same with closures. Sure, it's nice to know when you create a closure by accident, but using it on purpose? Come on. It's all hacks for implementing "private" modules.

Closures are handy for a number of things. Many event listeners are closures

    const [username, setUsername] = useState('')
    const onChange = event => setUsername(event.target.value)
    const onSave = () => dispatch(saveUsername(username))
    return (
        <input value={username} onChange={onChange} />
        <button onClick={onSave}>Save</button>
This code contains two closures

That's not JavaScript. Is it JSX?

JSX is just an extension of JavaScript. I wrote React-like code because that's very common right now but this would also be true for more traditional JS.

    const todoItems = []
    addTodoItem.addEventListener(event => {

1. React is a confusing mess of UI/logic mixing.

2. Where are the closures and what's the necessity to use them?

1. UI and logic are inherently mixed. It takes a lot of effort and design sense to partially separate them, and trying to completely separate them is ill-advised. If this is confusing, it’s due to the fact that making a modern UI is an inherently complicated problem (and not something that is just made more complicated by frameworks).

2. onChange and onSave are both closures.

It isn’t technically necessary to use closures, but you need to find the correct setUsername from onChange, and since setUsername isn’t a global variable, closures are the natural and easy way to do it.

React is a UI runtime^1, designed and refined for the purpose of managing what gets rendered, in a performant and maintainable way.

1. https://overreacted.io/react-as-a-ui-runtime/

Where else would you propose putting UI rendering logic?

> 1. React is a confusing mess of UI/logic mixing.

Hooks have shown that Super Serious programming can also be comedy, which is pretty cool.

Don’t think I get how React hooks are comedy. Can you elaborate?

They're low-level interfaces to a custom property and method lookup table in a language that already has that built-in. I guess it might just be me but I get a little chuckle every time I read/read-praise-about/use them.

I dunno, the functions-or-bust crowd happily doing and championing manual OO machinery fiddling amuses me.

Does that built-in method lookup table contain all the re-rendering and general state management work that React does with its hook?

Nah, but that could have been build on traditional methods and properties just as well, without having to re-implement those first. It's not like every component doesn't resolve to an instance of an object anyway.

[EDIT] what they couldn't have done, probably, would have been cleanly implementing that on top of class-based components without then having to tell their large and influential functions-are-the-only-way constituency that they'd need to write a lot more classes in the future. I suspect aversion to having to deliver that message is part of why we ended up with hooks as the solution, and classes left behind instead.

> what they couldn't have done, probably, would have been cleanly implementing that on top of class-based components without then having to tell their large and influential functions-are-the-only-way constituency that they'd need to write a lot more classes in the future.

They were saying that for a long time before hooks when the only way they had it implemented at all was for classes, and functional components were usable for much narrower use cases. I suppose, if they could have done it cleanly with classes, they would have, whatever that meant saying to those downstream who aesthetically preferred functions. I don't know if it inherently worked better with functions, if the core devs themselves are just more proficient in that style, or if it was just a confluence of experience and the timing that the push to improve functional components occurred, but in the end functional components are just much cleaner.

I can understand why it may seem non-optimal, but I don't have much of a dog in the fight, and I refactored a hobby project to react hooks a little while ago and found it both much less code and much less complicated. But to each their own.

> It allows people to write JavaScript following whatever approach suits them

This comment really looks like it's a reply to some article other than this one.

Realistically, do you think JS programmers are going to form two camps?

  x ** y 
  Math.pow(x, y)
I don't think so. I think people will just stop using Math.pow.

Nor do I foresee a big problem with some numeric constants being written with separators and others not.

In the unlikely event there's a problem with either addition, prettier can be enhanced to make it so developers don't need to be up to speed on them.

That's fair. My comment is probably off-base when it comes to the particular contents of this article.

I guess I was speaking more to a general fatigue with every new feature that is added to JavaScript/TypeScript.

What was so wrong with Math.pow(x, y) that we needed a new operator for it? I think this is a question that could be asked of many additions to JavaScript/TypeScript over the years, and I think every (well-intentioned) addition has contributed to the language's current kitchen sink.

New additions don't mean the old capabilities will go away (without breaking backwards compatibility). So yes, some developers will use the new power operator in net-new code, but all existing usages of Math.pow() will remain, and every new developer that learns JavaScript will now need to know both.

New additions don't mean the old capabilities will go away (without breaking backwards compatibility).

This is something any popular programming language has to wrestle with. There is a lot of merit in Python's philosophy of having one, and preferably only one, obvious way to do something. Otherwise, even if each different way is perfectly good in its own right, you still have more for anyone learning the language to know, and you get different representations of the same idea appearing in the same code base for no particular reason.

I do think JavaScript has more of a problem with this than most languages because of its rapid changes and ambiguous standardisation (the de jure of annual ES standards vs. the realities of what is supported in real time in each browser, or Node version, or Babel preset).

Does anyone really have time to check whether some new function on Array's prototype or some new syntax like the examples in this article is available in every target they need to support yet? I'm guessing most of us still use Babel in our build process for front-end code, even if the relatively new parts of JS we're using are supported natively everywhere we need them by now.

But then you get things like modules and imports, and you still find Node's story with these is a muddle. Things we've taken for granted for years now on the front end don't always work out of the box as you might expect on the back end, and there are at least two competing styles. And this is arguably the most important and fundamental tool a programming language needs for building larger applications!

Why would one check if the new syntax is available rather than just use browserslist? https://github.com/browserslist/browserslist-example#babel

For one thing, Node exists. If you are writing server-side or automation code, you probably aren't using tools like Babel and Browserslist.

Ideally, JS would have been based on S expressions and consistency would naturally flow from the syntax. But that ship has sailed, and occasionally it makes sense to add a new infix operator for succinctness. https://github.com/tc39/proposal-exponentiation-operator#inf...

With prettier, one can make an old style go away.

Some of us still have to support IE11, so I’m forced into the Math.pow() camp without adding a transpiler.

Is the power operation really used enough for this shortcut to be a meaningful addition? I’ve literally never used it in workplace code.

Prettier.js is fantastic. I don’t think it does any function remapping right now though, does it? Seems like a better fit for Babel.js, since its whole reason to exist is backwards-compatibility.

> Limited languages that support a single paradigm, and support it well.

Yeah, Python got this right when it said "There should be one obvious way to do it". It's a shame the language seems to have disregarded that part of the "Zen of Python" recently.

Nobody uses OOP in JavaScript imo (because otherwise, just use TypeScript) except when making games.

This link contains the biggest header ad I've ever seen. Is it on purpose? Or is it just on my machine?

Same on my machine. I ended up not reading the article due to the the ads. Generally I'll deal with them to support the content creator, but these were too much for me to deal with.

As a minor note—the exponentiation operator was added in ES2016 / ES7, not ES2015 / ES6. It wouldn’t matter, except you need to tell all your tools (Terser, etc.) that you are using ES2016 or they will throw syntax errors when processing your code.

tldr: If you don't want to scroll down the massive header and repeated statement of the title:

1. Double asterisk is the exponentiation operator.

2. _ can be used in numbers, e.g. 1_000_000

Also (and not in the article) both are also true in Python.


I was expecting this to be about object literal setters (and getters):

  const language = {
    set current(name) {
    log: []
Supported by browsers for fifteen years now.

Is there a good reason that ^ is not used as an exponent operator in most (all?) languages. Its used in every calculator Ive seen.

2^5 = 32

I speculate that ^ is used for xor in many languages for psychological compatibility with C, which is a very old language.

In SageMath, which uses a lightweight preparser on top of Python, I made it automatically convert ^ to , since otherwise mathematicians, who are used to LaTeX, would be very confused (I remember realizing this during a tutorial at Pycon in 2005).

C doesn't have an exponentiation operator, and instead uses `^` to mean XOR. Other languages have copied that meaning of `^` and hence need to use something different for exponentiation.

However, Lua is one language that does use `^` for exponentiation (its XOR operator is `~`).

Yes, it's often used for a XOR operation (bitwise exclusive or).

Could someone edit the title? As it stands it could be about literally any two features of JavaScript.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact