10 ms·
JavaScript is weird
- andrewfromx 3y agothis is the reason I pick a language OTHER than js for the backend. Why oh why did the whole world decide nodejs sever side js was a good direction? For the frontend I get it. Unless you are going to mess with WASM files you need js.
- rr808 3y agoI personally do not know much about JS other than some light projects, but I have worked on an application that was C# both front and backend and the productivity was higher than anything else I've worked on. Using the same language, same tools, same developers, same job interviews was great. I'm thinking of doing back end JS for this reason.
- foooorsyth 3y agoI think Microsoft’s web stack is underrated, and was perhaps a factor there as well. I’ve seen unusually fast products written in the “dreaded” ASP.NET. Visual Studio is a much more powerful IDE than vim/VS Code, and imo C# is a much more scalable language that vanilla JS. Typescript bridges the gap pretty well.
- moffkalast 3y agoThe fact that JS can be this stupidly wacky yet still be so enjoyable to work with that nodejs is as popular as it is says more about other languages than about JS, I think.
- thfuran 3y agoAre you sure people are using it because they enjoy using it?
- moffkalast 3y agoYes, I'm pretty sure. In my and my friends' experience at least. As long as the codebase is of manageable size it's one of the most laid back languages out there, letting you get shit done without having to write pages of boilerplate or being lectured by a compiler. The level of abstraction is just right for the current hardware too. I'll probably get flamed for saying this, but having all objects be hash maps that can be extended or edited at any point and be simultaneously dumpable and loadable into JSON with one line was an unfathomably big brained move. Being able to just use the data you get from various sources instead of having to create an ad-hoc struct/object that perfectly matches all types and values (and ofc crashes immediately if a change is made on the other end) is so underrated. That's not even mentioning the native async support.
- mohbk 3y agothe website is 90% problems of very stupid implicit type conversion, and 10% valid floating number behavior that exists in other languages too (0.1+0.2, NaN a number) I agree using plain JS anywhere is not a good idea, but Typescript (or js with ts annotations) is often ignored when it does a very good job of catching most of these issues, while offering a very flexible type system in a more mainstream paradigm
- paulddraper 3y agoNode.js is popular is precisely because browsers are popular and JavaScript is the language of web browsers. Reusing code, tooling, training is meaningful. --- Every language (Java, Ruby, Go, Bash, whatever) has quirks. JS may have more than others, but it's not alone.
- devbent 3y agoLike typescript, which is an amazingly good language with an absurdly powerful type system that is easier to learn that competing absurdly powerful type systems!
- deergomoo 3y agoCause people wanted to write their front-ends and back-ends in the same language, for various reasons (code sharing, economics of hiring developers, etc). My issue with JS (particularly but not exclusively server-side) is less that it has some weird aspects and more that its built-in functionality/standard library is incredibly barebones in many respects. IMO that’s the main reason why it’s considered normal in the JS world for a project to pull in hundreds/thousands of largely un-vettable dependencies.
- jakelazaroff 3y agoThis is the reason you don’t pick JS for the backend? I’ve been using JavaScript professionally for over a decade now and I’ve literally never needed to write +!![] or “” - - “” or even a single one of these esoteric edge cases. (Except the floating point weirdness, which is an issue in basically every language.)
- andrewfromx 3y agono i mean the fact that JS was invented in 1995 and isn't well designed because we didn't know what we know now. I'm a professional golang developer and it just feels obvious to me when writing go; wow, this language was well thought out and fixed a lot of mistakes from 1995. (In a way that TypeScript doesn't even come close)
- jakelazaroff 3y agoI really like Go, and I tend to prefer it to JS for server-side stuff, but when I use it there are a lot of things I miss about JS: - Error handling is onerous; I write a lot of functions where most of the lines are just checking for and returning `err` - No anonymous structs, and it’s really awkward to define structs inline - Dealing with collections is really verbose; I guess since generics dropped I could handle this in userland, but it’s not idiomatic etc etc. No language is perfect!
- andrewfromx 3y agoI think u might like my "go on rails" framework: https://many.pw/sd/ https://many.pw/sd/ I make heavy use of map[string]any vs structs. I also find the right balance of checking err vs just making it _
- WorldMaker 3y agoJS was better designed than people give it credit for or it wouldn't have lasted anywhere near as many decades without being replaced by something else. JS has also had a lot of its "mistakes" fixed since 1995. It does so in a backwards compatible way and it isn't always obvious how much progress has been made, but it has never been a static unchanging, "unfixed" language. (Personally, I'd much rather work with JS on the backend than golang. Golang looks to me like a throwback to the 1970s that misses good language design ideas from the 1990s. I understand some of why it has become popular, but there's so much bad design in that language that upsets my nausea.)
- danShumway 3y ago> Why oh why did the whole world decide nodejs sever side js was a good direction? Knowledge transfer, context switching, the stuff you already know. But there's also an interesting non-JS reason that's gotten forgotten because the serverside landscape has changed so much since the early 2010s. Node very heavily popularized single-threaded asynchronous request handling (ie, not starting up a thread for every request that came into the server). Of course there is nothing about Javascript that means it specifically as a language is essential for that pattern, but I remember hearing talks from Netflix employees and industry advocates about how much Node had improved their performance; I remember industry people coming to my college and talking about single-threaded serverside code and saying "you all need to check Node out." And there are downsides to asynchronous code (callback hell was the obvious downside that got brought up a lot before `async` or even promises had arrived in the language) -- but I remember among especially younger serverside developers this trend of people saying, "Node is just faster. That's why you use it, because it's just straight-up more performant than what you're currently doing." And I understand serverside devs from other languages can at this point jump in and say that it's not, that the single-threaded model is possible in other languages, that there are downsides to the single-threaded model, that Node doesn't do it well, whatever. I'm not arguing the point, I'm just describing the cultural shift I saw. All of the conversations about sharing code happened too, but I remember having conversations where people talked to me about jumping to Node specifically because Express was single-threaded and because it could handle more concurrent requests than other popular server architectures that they were familiar with. And I suspect that it gave the ecosystem a lot of momentum. Node's original purpose was in part an experiment to see if single-threaded async request handling would be able to handle large numbers of simultaneous requests. My somewhat-limited memory of the conversations that were taking place back then is that running the same language clientside and serverside was just the icing on the cake. The big reason people were excited was because Node was single-threaded.
- jiggawatts 3y ago> single-threaded serverside code and saying "you all need to check Node out." When Node started to become a thing, Java and C# has already been doing multi-threaded web servers for about a decade. Oh, and C# already had support for async programming too! Node become popular in part because Silicon Valley just doesn't seem to be aware of anything that exists outside it.
- esafak 3y agoDo they still call it "isomorphic"?
- joshmanders 3y ago> this is the reason I pick a language OTHER than js for the backend. You choose against a language because of code that any sane person, which I hope includes yourself, would never write intentionally? Weird flex, but ok.
- andrewfromx 3y agohttps://news.ycombinator.com/item?id=37111497 https://news.ycombinator.com/item?id=37111497
- azangru 3y ago> 0.2 + 0.1 === 0.3 This isn't just javascript though. It's harder to find a language for which this would be true than the other way around.
- mohbk 3y agoand typeof NaN == "number" is also part of the standard, it is valid to pass NaN to functions that accept numbers, and it's expected to propagate or change back to normal numbers (e.g. NaN^0=1)
- marcosdumay 3y agoIf anything, JS has plenty of problems due to its too literal interpretation of NaN.
- bee_rider 3y agoI mean, it is a weird statement in that the language apparently needs a === operator. Of course, after looking up what === is, the behavior is obvious.
- threatofrain 3y agoThat wouldn't change anything here. This behavior is due to the IEEE 754 number spec, which is implemented in many languages.
- bee_rider 3y agoThe floating point behavior is the obvious part, the === operator is the head-scratcher.
- kerkeslager 3y agoYeah, this is a IEEE754 floating point issue. I'm not sure why it seems there hasn't been any progress made on making floating point types less error-prone in the last few decades.
- bmacho 3y ago> This website is literally about JavaScript. I mean what did you expect, a .NET application? This website is 99.9% poorly optimized and highly questionable JS. And yet, you have JS turned off. I kinda expected text and code examples, on a blog. I forgot to check that this is a dedicated website about the weirdness of javascript.
- moralestapia 3y agoNo, JS is not weird, your code is weird. true + ("true" - 0) ? "" && -0 ? Like, can you tell me a language where it does make sense to "apply AND to an empty string and a (negative?) zero"? If you write code like this, you have much bigger issues than whatever you choose to write your code in.
- azangru 3y agoYes, I was about to suggest that instead of "JS Is Weird", the site would be more appropriately called "My inputs are weird".
- chefandy 3y agoIndeed, nobody would write this code to get the result shown— weird code is usually an accident, and errors informing you about accidents are way more useful than delivering some weird counterintuitive result just to avoid runtime errors.
- tylercrompton 3y agoI think that it can be both. Yes, weird code will produce weird results but in my opinion, the language should at least help one find the weird code.
- leeoniya 3y agoTypeScript is great for this, among other things. it actually aids in writing faster (more JIT-friendly) code by alerting you to these implicit type mutations/coercions.
- ruined 3y agojs being a dynamic language on the web with very "helpful" coercion logic, it is much easier to unintentionally perform such an operation than a non-js developer might expect typescript helps, but i have fired some of these footguns even with typescript.
- hn_throwaway_99 3y ago
- mmoustafa 3y agoMy favorite which wasn’t included is NaN === NaN -> false In fact that’s exactly how isNaN(x) is implemented under the hood. It compares the argument to itself.
- gmiller123456 3y agoThis is from the IEEE-745 spec. The rationale is explained at the link below by a member of the baord at the time. https://stackoverflow.com/questions/1565164/what-is-the-rationale-for-all-comparisons-returning-false-for-ieee754-nan-values https://stackoverflow.com/questions/1565164/what-is-the-rati...
- patrec 3y agoAnd as can be seen from the weak provided rationale, the IEEE-754 spec rather sucks. Javascript would probably have been a better language had it diverged from it.
- anamexis 3y agoAs another comment points out, this isn’t JavaScript related, it’s just how the semantics of NaN in floating point works. Because, conceptually, 0/0 is not equal to -inf + inf. NaN is not a semantic value (it is a lack of one), so you can’t do semantic comparisons with it.
- paulddraper 3y agoThat's true in most languages. The opposite is almost more surprising.
- patrec 3y agoThe only language I can think off that does the right thing is Eiffel (https://bertrandmeyer.com/2010/02/06/reflexivity-and-other-pillars-of-civilization/ https://bertrandmeyer.com/2010/02/06/reflexivity-and-other-p...)
- Groxx 3y agoI agree JS has a high number of quirks, but like 22 out of these 25 are "implicit type conversion is surprising". It's surprising in almost every language that does it to any degree. JS's is only slightly stranger than, say, PHP. About the only exception is "empty values are falsy", and even that surprises people pretty frequently, and can be used to construct highly confusing snippets of behavior.
- marcosdumay 3y agoMost are not quircks of implicit type conversion, they happen because of the "no errors, at any cost" phylosophy of the language. 1 + "five" is an error in PHP, not some random correct-looking value.
- Groxx 3y agoIn recent PHPs, yes, as they've gotten a lot more strict. On older ones though, it's not an error: https://onlinephp.io?s=s7EvyCjg5UpNzshXMFTQVlBKyyxLVbIGAA%2C%2C&v=5.6.40 https://onlinephp.io?s=s7EvyCjg5UpNzshXMFTQVlBKyyxLVbIGAA%2C... Even in the previous major version (7) it's only a warning. I agree that philosophy is likely the main cause of decisions like this, but JS is hardly unique in having it.
- chrisjj 3y ago> "no errors, at any cost" Meaning of course "no errors reported, at any cost". Programming language language has redefined "error" - to substantial cost to programmers.
- bennyelv 3y agoWhen your system gets to a certain size, this is absolutely fatal. Please halt and throw a massive exception, shrugging and carrying on makes bugs impossible to track down and the whole system unpredictable. It’s a philosophy that might be acceptable for a simple-ish frontend, but when if you try and build something significant it’s just awful. Source: I inherited responsibility for a > 5m LOC system written in JavaScript. The problems aren’t all JavaScript’s fault, but it does play a major part in it.
- pwb25 3y agoWho would ever code like this? Those kind of quizzes can be made for any language So tired of those smug "hurr durr language X hehe" posters
- bazoom42 3y agoAll practical languages has quirks, but JavaScript have significantly more quirks than the average language.
- yieldcrv 3y agoGet a linter
- bwanab 3y agoVery much why I write my front ends in Elm. It might be a PIA, but it shields me from quirks like this.
- bazoom42 3y agoNice! So what is the result of 0.2 + 0.1 in Elm?
- deleted 3y ago[deleted]
- ccvannorman 3y agoparseInt(0.00005) // 0 parseInt(0.000005) // 0 parseInt(0.0000005) // 5 parseInt(0.00000005) // 5 Huh??!
- amelius 3y ago0.00005 -> "0.00005" -> 0 0.00000005 -> "5e-8" -> 5
- Groxx 3y ago^ because: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... > The parseInt() function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems). Surprisingly, if you put garbage in, you get garbage out.
- marcosdumay 3y agoThe garbage obviously being the language's std library.
- RadixDLT 3y agono no no, python is weird
- threatofrain 3y agoSlightly challenging one. Find the potential bug. const arr = [1, 2, 3, 4, 5] for (let i = arr.length - 1; 0 < i; i--) { const j = Math.floor(Math.random() * (i + 1)) [arr[i], arr[j]] = [arr[j], arr[i]] }
- genezeta 3y agoNot potential: Uncaught ReferenceError: can't access lexical declaration 'j' before initialization Semicolons aren't that bad.
- XeO3 3y ago> In general, if a statement begins with (, [, /, +, or -, there is a chance that it could be interpreted as a continuation of the statement before, if semicolon isn`t provided. While /, +, and - are rare in the beginning of the statement, ( and [ aren't.
- WorldMaker 3y agoThat list is missing ` from ES2015+ template literals. I enjoy teaching this to junior developers as the "winky frown rule" because that is a silly name that sticks in your memory and does help you remember it. Lines that start with an emoticon frown must wink: ;( ;[ ;`
- tedunangst 3y agoBut no mention of "dog".sup()?
- ssalka 3y agoMy favorite weird JS thing: ['10', '10', '10', '10', '10'].map(parseInt)
- open-paren 3y agoBut even that isn't weird, since parseInt() takes two arguments (string and radix) and map expects a function value that receives three arguments (value, index, and the whole array). It's not so much "weird" as it is "I didn't read the docs“.
- xigoi 3y agoIt's weird because someone coming from a functional language like Haskell would think that the anonymous function in the following code is redundant, while in fact it's necessary: ["10","10","10","10","10"].map(x => parseInt(x))
- zarzavat 3y agoIt’s nothing to do with the language being functional or not. It’s because JS supports optional arguments. Haskell doesn’t support optional arguments which is why this is impossible in Haskell, but that is a huge trade off since optional arguments make it easy to evolve an API over time without causing breakage. It’s a known good practice in JS to always wrap callbacks with a lambda in this situation. Even if you don’t, usually the type checking will catch it, this bug only works because the second argument is a number to both functions.
- tome 3y ago> optional arguments make it easy to evolve an API over time without causing breakage Defining functions with new names also make it easy to evolve an API over time without causing breakage.
- zarzavat 3y agoIt does tend to make code less readable however if you end up with several functions that do the same thing except that they were defined at different times with different numbers of arguments. It’s not always clear from the perspective of the API user whether the difference is just the number of arguments or if there are other differences too. Optional arguments communicate that intention more explicitly. Looking at, e.g. the Python standard library a large number of functions have arguments that were added after the function was first defined. If Python didn’t have optional/keyword arguments then the number of API calls would be substantially larger.
- mitchbob 3y agoRelated and fun: https://www.destroyallsoftware.com/talks/wat https://www.destroyallsoftware.com/talks/wat
- Aerroon 3y agoMy favorite thing about js that I recently learned is this: var arr = []; arr[2] = 2; // now arr is [empty, empty, 2] arr[-4] = -4; // now arr is [empty, empty, 2, '-4': -4] arr.length; // is 3 arr["foo"] = "bar"; // [empty, empty, 2, '-4': -4, foo: 'bar']
- moritzwarhier 3y ago> // now arr is [empty, empty, 2, '-4': -4] I'm not sure because I'm not at home, but did you verify this pseudocode? Pseudocode doesn't have to be valid syntax, that's the point pf course. But it should bring the point across regarding the behavior of actual programs, no? AFAIK, unquoted colons inside of array literals in JS are illegal. I'd understand it better if you had written sth like {"0": undefined, "1": undefined, "2": 2, "-4": -4} It is fairly clear that you are opting out of all optimizations applicable to what Array.prototype is meant for in JS. The distinction between "empty" (in this special case, sparse arrays) and the primitive value "undefined" is similar to the difference between non-declared and undefined variables when not using const/let — which every one should do IMO, along with ES Modules instead of legacy node- or bundler-specific module syntax. Also, using var in 2023 makes only sense to me for two cases: - REPL context wishing to redeclare identifiers other than functions defined using the function keyword - very legacy browser Targets, < latest IE11 Sparse arrays are, just like var, a historic relic. I have never encountered any code where sparse arrays were intentionally used or appeared at all. Arrays are objects in JS, yes. You can construct a sparse array using Array.from({length: 5}) "sparse arrays" are generally confusing and seldom desirable. And JS is honest that it's an interpreted language where "arrays" are not even required to have a uniform member data type - which of course is very advisable for reasons that go beyond code readability. But let's be honest, is (i.e.) PHP more clear in this regard? Personally I hate PHP's mishmash of arrays and maps ways more than the JS version. Both are syntactical sugar for memory-managed and heavily optimized "map" like objects where the keys are restricted to primitive types. Personally, I like that JS at least has a usable notion of strict equality and makes it easy to understand when values are references (always, unless they are primitive). PHP's copy-on-write behavior, reference operators and the mishmash of "associative" and "indexed" arrays are much harder to actually understand and bigger footguns IMO. JS has massive quirks, but what you show is not surprising for anyone doing JS with a modicum of proficiency. JS is a scripting language. People tend to forget this because of fast JIT compilers and because of TypeScript, I guess. Sparse arrays are a relic and the differences between your "empty" and the actual primitive value "undefined" in JS are not of any practical significance in my opinion. It's really a wart, but not one of practical relevance. At least this differentiates this from "problems" like ["1","2","3"].map(parseInt) that are really just a lack of basic syntax understanding.
- keithalewis 3y agoSomeone should write a book about this [0] and a tool to automate checking your JavaScript code [1]. [0]: https://www.oreilly.com/library/view/javascript-the-good/9780596517748/ https://www.oreilly.com/library/view/javascript-the-good/978... [1]: https://www.jslint.com/ https://www.jslint.com/ I'm working on a book called "How to not get your knickers in a twist because you neglected to learn from people who came before you."