Hacker News new | past | comments | ask | show | jobs | submit login

Javascript is not simple AT ALL.

It has 3 ways to declare functions, multiple variations on arrow functions syntax, a weird prototyping inheritance system, objects you can create out of "new" on functions, object literals that can act an pseudo-classes, classes, decorators, for-i loop + maps + filter + for-in loop (with hasOwn) + forEach, async / await + promises and an invisible but always-on event loop, objects proxies, counter-intuitive array and mapping manipulations, lots of different ways to create said arrays and mappings, very rich destructuring, so many weirdnesses on parameter handling, multiple ways to do imports that don't work in all contexts, exports, string concatenation + string interpolation, no integer (but NaN), a "strict mode", two versions of comparison operators, a dangerous "with" keyword, undefined vs null, generators, sparse arrays, sets...

It also has complex rules for:

- scoping (plus global variables by default and hoisting)

- "this" values (and manual binding)

- type coercion (destroying commutativity!)

- semi-column automatic insertion

- "typeof" resolution

On top of that, you execute it in various different implementations and contexts: several browser engines and nodejs at least, with or without the DOM, in or out web workers, and potentially with WASM.

There are various versions of the ECMA standard that changes the features you have access to, unless you use a transpiler. But we don't even touch the ecosystem since it's about the language. There would be too much to say anyway.

There are only two reasons to believe JS is simple: you know too much about it, or you don't know enough.




I feel like a large slice of JS’s complexity comes from footguns you aren’t really supposed to use anymore; whereas with C# the complexity feels quite layered, multiparadigmatic, something-for-everyone, syntactic-sugary. But I probably know too much about JS and not enough about C#.


At least in C# you can ignore most of it and the complexity doesn't really come from numerous foot guns. You can still write Java 1.6/.NET 2 style C# code just fine, it's all there. The rest of the features can be fully ignored and they won't hurt you.

But then again the newer features they do make writing code a lot nicer, giving more compile time analysis warnings etc hopefully resulting in slightly better code. And the new features also enabled a lot of performance improvements in the runtime which is nice. .NET 2/4 wasn't all that fast, .NET 8 can be a lot faster.


You can still write ES5 and it will work in the latest JS runtimes, so I'm not sure how this is different.

Further, indeed the newer JS features do in fact give you better compile time analysis, warnings, etc, and result in slightly better code.


You can even write ES3 and it should work in all web browsers.


Well, all the people that used JS 15 years ago followed Douglas Crockford advice very much to heart.


Crockford hates TypeScript and loves og JS. He thinks the push to turn JS into c# is misguided and a waste of the original small talk-y beauty of The Good Parts - src he said as much to me at a lunch I went to where he was also attending.


Does Crockford "like" OG JavaScript? He's most famous for writing a book that shits on how much of the language should be ignored and avoided. To be fair, a lot of that was right, but it's far from comprehensive for the language we have today. Seems like despite another decade of improvements on the language The Good Parts lives on in the minds of readers as something relevant today-- while a new treatise on The Good Parts of modern JS is not present. There are definitely parts of JS today that should be discarded, like "var", but The Good Parts cannot help you with that, because when it was written you could not discard it, as there was no other option.

I've seen developers make complete messes of codebases that when using modern JS features would be mostly trivial, and they hide behind The Good Parts to justify it. And this includes suggesting that classes are somehow bad, and avoiding them in favor of POJOs and messily bound functions is preferrable despite JS not receiving a dedicated class concept until years after The Good Parts was published...


Does TS make JS non-smalltalky? Static typing which is optional.. and you still get a REPL, online compiler and the ability to dynamically inspect objects in your global object...


v1 of TS had a heavy "OO"/class-based bias to it, v3 and v4 made it viable for real-world JS code but peoples perception stayed both due to those who looked early on seeing something they didn't like or the code produced by many who loved it early on.


> the original small talk-y beauty of The Good Parts

Javascript seems much, much, much closer to Lisp than to Smalltalk. Granted, all three are very dynamic, but message passing needs to be bolted onto javascript. Meanwhile pretty much all of lisp is included "for free" (...via some of the ugliest syntax you've ever used).


Totally agree, if JS had further leaned into it's smalltalk-y-ness and ended up with dynamism similar to Ruby for example, I'd actually be really happy with it personally. True message passing and more metaprogramming features allowing you to change execution context would be fun to play around with in a forked version of JS somehow.


How long ago was this? TypeScript v1 and v2 definitely had a class-based stink to it since the typing system only handled those scenarios somewhat well.

Right around when I started using it (mid 2019) there was a bunch of V3 releases that each on it's own might've not seemed like much but they all improved small parts of the engine that made it easy to get typing on most of your code if using a functional style without adding maybe more than a few type declarations and some functions typings.


I'm all for people writing functional code with Javascript-- but when people eschew classes because of their "stink" and proceed to use all of the stateful prototypal archaic features of JS instead of classes, I have to protest. If you are using this and function binding and state extensively in your "functional" JavaScript, you are reinventing classes poorly. And classes are a part of JS itself, not something added on to JS by Typescript (in the current day).

The Crockford crowd would like us to live in a world of ES5 as if that's some kind of badge of pride, while justifying it with a warcry of "functional", while breaking the preconceptions of functional programming all throughout.


My point was rather that a functional style with plain old data was always preferable, the "stink" was that early TS versions _favored_ non-functional OO style that suited the TS type system at a time when most modern JS code already had a functional approach, so you ended up writing non-idiomatic JS because the TS type system wouldn't handle idiomatic code (this also contributed to a lingering distrust in TypeScript that persists to this day despite the upgrades to the typing system).

Personally I prefer neither prototypal or classes, 90% of the time you just want the interfaces, unions or inferred types and the few places where you actually want inheritance and/or object methods you really are just better off with a factory method that then creates a literal that is used or suits an interface.


Using JS/TS in a functional style doesn’t mean using prototypes or function binding or anything. I’m not sure how you inferred that from the comment you’re replying to…it just means using plain objects (TypeScript even, a little awkwardly, lets you express ADTs) and plain functions, perhaps with the module system to organize them.


Classes are still built around prototype inheritance, there are some differences, however they are still an easier to use api on top.


Yeah, iirc private properties (added in ES2022) are currently the only part of ES6 classes that can neither be created nor accessed using prototype-based code, to the consternation of some people when they were added. Of course, provate properties can still be readily emulated with a WeakMap in a function scope.


> I feel like a large slice of JS’s complexity comes from footguns you aren’t really supposed to use anymore

I'm not inclined to use a language that can't be fixed.


Hmm, I understand what you mean. But I think there's a difference between complexity and optionality / versatility.

For example, it has different ways to declare functions because assignment is generally consistent (and IMO easy to understand) and the "simplicity" of Javascript allows you to assign an anonymous function to a variable. However, you can also use a standard function declaration that is more classic.

But I do understand what you're saying. If anything, I think it's generally in agreement with my feelings of "Javascript doesn't need to be more complex."

> There are only two reasons to believe JS is simple: you know too much about it, or you don't know enough.

This is hilarious and probably true. I think I am the former since I've been working with it for 20+ years, but I also think there's a reason it's the go-to bootcamp language alongside Python.


I do appreciate the modern features a lot personally, and the fact they have been added without breaking the world. Interpolation, spreading, map and arrow functions are a huge usability boon. Plus I'm glad I can use classes and forget that prototypes ever existed.

But I train beginners in JS and boy do I have to keep them in check. You blink and they shoot their foot, give the pieces to a dog that bite them then give them rabbies.


In fact, Javascript is so complex that one of the seminal books on it was specifically "The Good Parts", cutting down the scope of it to just the parts of the language that were considered decent and useful.


I think the distinction with JavaScript compared to other 'complex' languages is that you don't have to go beyond "The Good Parts" to achieve significant functionality, and it has become idiomatic to use the good subset.

In some respects I think if there were a well defined "Typescript, The Good Parts" I would happily migrate to that.

I do wonder if there will, one day, be a breaking fork of JavaScript that only removes things. Maybe a hypothetical "super strict" might do the job, but I suspect the degree of change might not allow "super strict" code interacting with non "super strict" easily.

BiteCode_dev has provided a pretty good summary of a lot of the issues. A lot of them have easy fixes if you are prepared to make it a breaking change.


ESM is the closest to a major version for JS. It forces strict mode, which includes many non-backwards compatible changes [0]. Most notably, it removes the `with` statement. Other examples of removals are octal literals or assignments to undeclared variables.

[0]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


Yep, it's going to take time but eventually one day the vast majority of JS code in the wild will be strict mode and the non-strict stuff will be de facto deprecated and not expected to work everywhere


That's certainly true when writing code, but when you are reading code someone else wrote that flies right out the window. This is hardly a unique problem with Javascript, many languages get tagged as "write only" because there is such a large array of available features that you never know which subset someone is going to use. C++ is notorious for this for example.


> BiteCode_dev has provided a pretty good summary of a lot of the issues.

Around half of that list is things added later that were supposed to make the language easier to use.


after the success of the Good Parts book there were a few other books with the "Good Parts" in the title - like HTML and CSS the Good Parts, and Java: The Good Parts. I seem to remember looking through PHP: the Good Parts and feeling that it was just a learn PHP book, that it did not really differentiate between any core good parts of the language, the parts you should really learn and use.

I sure would like a real "Good Parts" series of books.


> reasons to believe JS is simple

it's because people are talking past each other, and that's because people are using language wrong, and are merely talking past each other. The word simple is often used to mean "easy" or "familiar".

Simple is very different from easy, and familiar things are easy but doesn't have to be simple at all.

javascript is not simple, but it is easy.


> using language wrong

There is no wrong use of language; there's just people who don't bother to communicate well in the most effective language available. In this case you could simply cohere the two viewpoints since you have insight rather than blaming one party and calling them wrong (...which is wrong).


> There is no wrong use of language

Thy can'n't sirus be. language works only farso as withbreathings we follow, Leading paths through gardens means fail, and bloom'st chaos wear not!


I don't think that's a serious barrier in this case. The above poster just would rather dismiss a statement rather than give it serious thought. It's easier to simply claim to know the one true meaning of "simple" rather than actually communicate effectively.


> rather than actually communicate effectively.

what's more effective than having a pre-defined term be what it means, rather than what the speaker intends internally?


> what's more effective than having a pre-defined term be what it means, rather than what the speaker intends internally?

Trying to understand the speaker, presumably, and not wielding your pet definition like a semantic argument. It's fundamentally boring conversation with no benefit to either party and it makes you look like an illiterate ass.


It's on the list of languages that used to be simple, I think.


Yes, but when "the good parts" came out, half of this list was already true.

There is a reason we ignore a good chunk of the language to be productive with it.


Not just half of it, the central part of it. Javascript did not grow into something huge, it started that way. A prototype based wannabe Java that accidentally (?) shipped with a full scheme included alongside. The latter of which remained mostly dormant until "the good parts" came along and put them into the (deserved) spotlight, relegating the prototype stuff from idiomatic to niche, for when you are doing something particularly clever. It's a unique mess that has lead to something no purer language could dream of.


It would have worked out fine if we managed to lose the prototypes without ramming classes into the language and baiting all the Java dickheads over to the web ecosystem.

Javascript breathed it's last breath the moment someone saw NestJS and said "wow that's a good idea".


> Javascript breathed it's last breath the moment someone saw NestJS and said "wow that's a good idea".

I still don’t understand how someone looked at Spring and thought “Wow, that’s pretty good! I’ll bring it to platform that has worse performance than Java, to language that was designed with dynamicity in mind and has no native static typing”.


Asking out of curiosity. What's your rationale behind Spring is slower? Worked on couple of greenfield and existing Spring Boot applications and we never had any performance issues caused by Spring. Spring has its own bad parts but calling that it has worse performance than Java is not one of them. Its not even a valid comparison. Java is crazy fast for a VM based runtime AFAIK.


Java is faster than Node.

You take slow framework, like Spring, and put it on slower runtime (Node) so you get double slow with less benefits.


> shipped with a full scheme included alongside

Sorry, what?

https://journal.stuffwithstuff.com/2013/07/18/javascript-isn...


The "scheme inside" might be missing the mark in any number of features, but in the end the resulting effect it had have been profoundly, well, effective. It's there.

People have been going all SICP (Abelson/Sussman) on JS ever since Crockford exposed the hidden scheme (or hidden not-scheme-at-all, if you insist) and moved JS far, far away from the humble prototype OOP it started as. And that had little to do with any language extensions that had been creeping in very slowly given the lowest common denominator nature of web development, and everything with the funky scope binding tricks that generations of programmers had been taught in the memorable "let's make Scheme OOP" drills of SICP and the MIT course (that so many other universities based their teaching on)


>There is a reason we ignore a good chunk of the language to be productive with it.

The same can be said for most languages, even assembly language, and especially so for C++.


This is true, but what's also true is using biome or eslint more than half of your complaints are gone. JS has always had bad parts, but today it's a lot easier to avoid them thanks to linters. And if you do stay in the good parts, it's my favorite language, for many reasons.

That said, I hate the constant stuffing of features (though not this one which is much needed), more stuff around JS like WebComponents, or CSS adding a ton of sugar.


I think what saves JS, like Python, is that despite the modern complexity, you can start to be productive in a few days with just the essentials and learn the rest with a smooth curve, slowly as you progress.


>Javascript is not simple AT ALL.

I prefer languages with a small instruction set, as then you can learn all you can do in the language and hold it in your head. JavaScript used to have a small instruction set, I don't feel it does any longer.

Aside from this I don't know that I see any benefit to these structs, although perhaps that is just the article doing that whole trying to write JavaScript like Java thing that making classes and constructors enabled.


Even if you think Javascript is already complicated, that isn't a reason to make it more complex.


Complexity isn't bad. If you have a simple language and you have to something complicated then you still have complexity, it's just expressed differently and uniquely in every code base.

Java doesn't have unsigned integer types because that is "simpler" but that doesn't remove the need to deal with unsigned integers in file formats and network protocols. But now you have to do a convoluted mess of code to deal with that. I'll take a complex language that solves real problems over a "simple" language any day.


That is still pretty simple as far as mainstream languages go.


You are not wrong, but a lot of the stuff you mentioned is literally a non-issue with any modern JS environment.

It feels like any old language gets this way...


And ESM vs CJS. What should be an inconsequential transition, has turned into a minefield where adding a dependency to your package.json might blow up your build system, testing library or application without warning. Literally wasted weeks of my life debugging this pile of poop that is the JS ecosystem.


Is this really a JS or a Node issue though? We have no such issues with Bun.


I guess technically Node, but in practice JS, since Node is still the de facto standard non-browser JS runtime. "Just use X" where X is some other build tool/runtime/testing ecosystem is another weird trope that's somehow considered acceptable advice in JS, but would be a massive undertaking for any non-trivial project.


Maybe if someone suggests Deno or similar, but Bun is a drop in for Node and is as such completely interoperable with your Node code. Its similar to how you can adopt PNPM easily because it’s a drop in for NPM, where as yarn and others are their own things.


3 ways to declare functions? I am probably blanking but I can only think of:

``` function foo () {} const foo = () => {} ```


    function x() {/* ... */}
    const x = function() {/* ... */}
    const x = function foo() {/* ... */}
    const x = (function() {/* ... */}).bind(this)
    const x = (function foo() {/* ... */}).bind(this)
    const x = () => {/* ... */}
    const x = () => /* ... */


Apart from hoisting (which has little to do with functions directly) and `this` these are all equivalent


Not sure if it counts but there is `new Function("return x;")`


Doesn't `function* ()` count?

After all, you can add a `*` to any existing function without a change in the function or its callers.


4 ways


5 ways, the arrow functions have two different syntaxes:

  () => { return 1; }
  () => 1


That’s still one way - arrow function.


Well, these have the same result, so if the two types of arrow functions don't count as different then neither should these two assignment versions:

  const foo = (function() {}).bind(this);
  const foo = () => {};
Edit: And speaking of assignment versions, there's a new comment that adds a third of the same. I kinda get the feeling a lot of the "multiple ways to declare functions" is just people who don't understand how the pieces of javascript fit together and think these are all independent. They're not. Just declaring a function has only a few ways, but declaring a function and giving it a name multiplies that out to some extent.

In javascript, functions are first-class objects: they can be assigned to variables and passed around just like numbers or strings. That's what everything except "function foo() {}" is doing.


`const foo = function() {}`


Do function expressions count?


const x = { foo() {} }


Why did JS's with keyword not work out while similar constructs in Python and Ruby were fine?


Python's `with` and Javascript's `with` don't do the same thing. In Python it introduces a context, which is a scope within which certain cleanup tasks are guaranteed, which improves the ergonomics of things that require you to close() at the end, similar to `defer` in Go. In Javascript it allows you to access object properties without prefixing with a name, which leads to confusion about scope.


JavaScript is simple in comparison to other languages. Not many people would disagree.


Yep and TS has all of that plus a gigantic layer of bullshit on top.

The web development community has created the perfect environment for nobody to ever get any work done while still feeling like they're being productive because they're constantly learning minutiae.


Typescript is the best thing to happen to JavaScript since ES6


Types are great, but I prefer Not having to transpile everything. Stepping throught the TS Code with a Debugger ist non trivial.


You can use 90% of typescript from pure JavaScript: https://www.typescriptlang.org/docs/handbook/jsdoc-supported...


I'm not sure what setup you have, but debugging TS code is pretty trivial. I use vite for all my projects at work and when running the dev server there is seamless integrations with the debugging dev panel in Chrome or Firefox.


Source maps solve this, it’s not a problem in practice


If only it had a sound type system.


It has a very good type system, imo better than most "natively" typed languages.


Hasn’t caused me any practical problems


Yeah I was almost gonna say it makes this proposal feel redundant. I can enforce object shape pretty well using TS, not sure why we need another OOP like thing that tries to do the same.


Typescript doesn’t tell the JS runtime anything about what it knows


Yeah I recommend reading “JavaScript the good parts” and don’t use anything far beyond those. Instead of “compile-time safety guarantees” by these vendor-lock-ins-masquerading-as-open-source, just use the language as it was designed: dynamically, and unit test—because you’re gonna be doing those anyway.


This, except for:

> There are only two reasons to believe JS is simple: you know too much about it, or you don't know enough.

There is only one reason to believe JS is simple: because you don't know enough.




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

Search: