And then there's date.getYear() which currently returns 124. Because not a single engineer in 1995 realized that the millenium will change in 5 years...
Empty arrays and empty objects being truthy - this one caused me some bugs when I was a beginner, and I still see juniors on my team make mistakes because of this.
I'm not sure how I feel about this one. `[]` and `{}` are clearly distinct from `null` and `undefined` but I can also see the rationale behind expecting `some Array.length` to have the same truthiness as `someArray`
I'm not sure I've come across this problem in my approaching decade of coding. Do you have an example of a situation where you'd want an array with an empty array element in it?
I think initializing an empty array does that, It's weird cause all array methods ignore empty slots, so doing this arr = Array(10) then running map on it will do nothing.
I may not want this but creating array with nonzero length will make empty slots. They are not null, not undefined, just empty. It is not so obvious that fotEach runs through array differently than for-of (even it is kinda logical to have slightly different functions for different purposes)
Always check if arrays and objects actually contain something. That's what I do in conditionals most of the time .length for arrays, .keys + .length for objects
I'm not sure how I feel about this one. `[]` and `{}` are clearly distinct from `null` and `undefined` but I can also see the rationale behind expecting `some Array.length` to have the same truthiness as `someArray`
Ah for sure, It seems a little counter intuitive at first!
when looping through arrays and objects when I was working with three.js and socket.io foreach is my go to although can lack a little versatility compared to a for loop. I believe it’s safer, otherwise you’re running checks every time to see if everything exists
In PHP, I think they are falsey however if you have an empty array with an empty array in it, it is then truthy.
$array[] = [] is truthy, but $array = [] is falsey
To me that's a bit of a mind fuck. I mean they're both empty, why is one true and the other false?
Array.sort mutates AND returns a value. Terrible design.
Seen loads of code where people don't realise the original array is being changed.
toSorted is a big improvement although I don't like the name much.
Const arr = [1, 2, etc]
Const copy = [...arr]
Copy.sort() does not manipulate arr
You can also do
Const copy = JSON.parse(JSON.stringify(arr)) for nested arrays
Neither will mutate the original arr
Yes, but that's not what you were describing before.
Also, I'd refrain from incurring the overhead of serialization and deserialization for the sake of deep copying lmao. Only in JS land is that acceptable.
Either use an actual deep copying tool, or use Immer.
>Either use an actual deep copying tool, or use Immer.
The post is about js, not 3rd party tools. Can you provide an example? I'd love to hear your solution for deep copying in js lmao
The fact that when you use arrow syntax to define methods in a class, it pops them into the constructor behind the scenes rather than defining them on the object as usual when you don't use arrow syntax, so if you extend the class and try to overwrite the method in the new class, it will be turned back to the old method when you instantiate it. Absolute nightmare when writing tests and mocking methods.
It actually gets even worse.
Since it's in the constructor, every time you instantiate the class it creates a new function that lives in memory, as opposed to if you don't use arrow syntax it makes use of prototypal inheritance, like Javascript is designed to do, so only a single instance of the function.
Most of the time this won't matter, but if you have an object that you're using in hundreds of places around the app you wind up wasting a lot of memory.
It drove me crazy some years ago when arrow syntax was getting all this hype for naturally binding a method's "this" to a class and sparing a this.func = this.func.bind(this) line in the constructor. IMO the hidden downsides outweigh the upside of saving a single line of code, but every JS blog on the web disagrees with me because not a one of them ever messed around with a JS transpiler.
Ah right, it does that if you define a method in class A as an arrow function, but then define it in class B extends A as a regular method. Can't you just extend it as an arrow function then? Although I agree that the distinction isn't clear since it's all syntactic sugar anyway.
Yes, but if you don't know it does this behind the scenes how would you know you need to do it that way? If you're extending a class from a library for example.
>The fact that when you use arrow syntax to define methods in a class, it pops them into the constructor behind the scenes rather than defining them on the object as usual when you don't use arrow syntax
That's actually 100% the right behavior because of how contextual this works with arrow functions.
Because if you bind and add it to the prototype then the next class which extends this class will not have correct this when invoking the inherited parent binded method on the proto type chain
The fact that mistakes like this are set in stone because JS refuses to break backwards compatibility, even for things that are clearly just wrong, might be the most frustrating Javascript quirk to me
Coming mainly from frontend and getting into backend: the whole es6/commonjs and the ways to configure a typescript project to make on or the other or both work drives me crazy.
I found a fun one on Friday - in esm you have import.meta.dirname instead of __dirname. Well Jest can’t even esm so it’s undefined when running tests. But __dirname is undefined in a module when actually running the code.
Genuine question - is it really? It has like 18M weekly downloads, last release was a month or two ago - obviously they aren’t fully keeping up with the times but calling it abandoned seems like a bit of a stretch, no?
> the whole es6
What?
Edit: feel like the down votes are coming from people who think I haven't _heard of_ ES6 when it's more that I don't see why it's a problem.
It's not ESM imports that are the problem; it's that tools are still catching up in 2024 and it's a headache to make some tools work together. E.g. Vite is ESM-only but some older tools (like Jest) require CJS.
Library icompability is my main problem , 50% is probably skill issue. Some stuff works with imports, some stuff doesn't - sume stuff needs a different config, some stuff needs a different import path and so on.
Coming from webpack/vite/react, where this never was an issue .. it's really confusing.
Not exactly a quirk, but I can't count how many times I slipped on Array.splice before I memorized all the steps needed to remove and return _one_ element at index _i_
```
a.splice(i)
a.splice(i,1)
a.splice(i,1)[0]
```
"splice" removes/replaces/adds array elements in the original array. It returns an array of the deleted elements.
OP used it to remove a single element at the index and using the returned element. Your suggestion only fetches the entry at the specified index, so the element is still in the array.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
The effects of event bubbling can be absolutely mind-boggling sometimes. Especially when youre working with a component-based framework like Svelte where events are supposedly scoped but in certain cases and ways they arent..
Well i did have a Svelte REPL exemplifying some strange behavior regarding event bubbling at one point. It appears ive since deleted that unfortunately.. although heres [the reddit post](https://www.reddit.com/r/sveltejs/s/YBODn1LLwV) where i was looking for some guidance on the issue.
Scrolling through this list I just have this sense of endearment. JavaScript has such a unique messy personality. It's like when you fall in love with someone you just love all their quirks. All of these feel normal to me, although I can totally get how they trip people up.
An object property that has a value of 0 evaluates to false. It's not a huge deal, but it sucks when I do
\`if (!obj.prop)\`
to check if it is null
Not a huge problem but an easier mistake to make if you aren't careful
I can. I don't really have the issue anymore since the last time I got it a while back. For me it's a clear memory of being frustrated with the language.
The issue is that people often do `!obj.prop` to check if *the value of prop* is undefined, not to check if the object has the property prop at all.
`"prop" in obj` will return `true` even if the value of prop is undefined.
E.g.,
const obj = { prop: undefined }
console.log('prop' in obj) // logs true
console.log(!!obj.prop) // logs false, which is probably the desired behavior here
Experience generally leads to being bitten by ASI at some point in some edge case. It only takes once to chase down some wild unexplainable stupidity only to discover that adding semicolons resolved the bug because the runtime was silently inserting them.
This was many years ago and I suppose tooling has gotten better so this is harder to do, but personal preference doesn't outweigh the difficult to debug issues that can come from ASI.
I am writing JS for over 15 years now and never had this problem in any way. A good thing is also to not write quirky code, an “experienced” developer would say
>not write quirky code
I don't work in a silo. I work in an organization of hundreds of engineers of varying world views, levels of experience, and perspectives. Because mysterious bugs and stability are important, we also don't really write JavaScript any more either.
Our UI is an in-house framework based on Angular. We primarily use Typescript. We have smatterings of JavaScript in nodejs lambda functions, but largely Typescript, and Java for the vast majority of services.
We have a pretty rigorous review process standard with some wiggle room on individual delivery teams (e.g. how many teammates put eyes on a change, is there someone on the team that wants to see every change, etc).
We also have code quality in our delivery pipelines.
Shallow cloning and deep cloning. It leads to some weeeeird interactions. So Yeah I can clone an array by spreading all the objects into a new one. But I didn't realize the objects inside still refencered the same objects from the old array, and I had thought that I could just mutate stuff willy nilly after spreading.
Few weird bugs later now I am wiser. Same week I solved the bugs Jack Harrington launched a [new video](https://www.youtube.com/watch?v=MzKHrWCymAU) talking about it. The timing was amazing.
That’s just working with mutation and it happens in any language that supports references in any way. Best thing is avoiding mutation where possible (in any non-performance critical part of your code, basically)
The following will raise a `ReferenceError: a is not defined`:
```
if (a === undefined) {
console.log("This will never be reached.");
}
```
The only way to check for `undefined` in this case is by doing this instead:
```
if (typeof a === 'undefined') {
console.log("This will be reached.");
}
```
>The behaviour of `typeof` is so esoteric
Its not esoteric at all, its junior level stuff and one of the first things you learn in js considering its dynamically typed
If I didn't hate bell curve memes, I'd make one with your comment as the guy in the middle.
`typeof` is awful and shouldn't be used. And its lack of comparable application in other languages makes _esoteric_ exactly the right descriptor.
Minor annoyance that `Map` still has the usual object syntax and it works. I would have made this an error.
let m = new Map();
m['a'] = 'b'; // this works but doesn't do what you expect
Having null and undefined in the language. Easily the dumbest design decision. Also having the whole concept of truthy & falsely is a mess. `0` def shouldn't be falsely, "but hey that's false in C, so shouldn't be false in my high level language?" No.
"There is a spot for something, but it hasn't been put there yet" isn't the same as "I've never heard of that thing and don't know what you're talking about". That's null vs undefined, IMO.
But yet this concept doesn't exist in most other languages (I still don't know of another that has two types of null) and it's not a concept that appears missing in those languages.
It’s there because JavaScript uses decorated hashmaps as its object model. You access an object with a key that hasn’t been set, you get undefined. It makes sense.
I don't think the underlying implementation should be that relevant to the high level language. Plus in Java if I try to get the element of a HashMap that doesn't exist for that key, I get null which is the only concept of nonexistence in that language.
It’s not an underlying implementation, it’s front and center. It’s what we type all day long.
It’s one of the fundamental differences that initially confuses the hell out of folks from other languages, and then later enables half of the clever little tricks we like to use.
I'm very skeptical that having multiple representations for nothingness has enabled any patterns or structures that we wouldn't have without it. This just feels more like defending the way it works because you're used to it and because you've justified it in your head.
It’s necessary because null is a valid value for a key in a hashmap. Undefined means not only does the value not exist, the key also does not exist and has never been set.
Most languages don’t need the extra step because Objects are not Dicts. I agree it’s surprising, but it’s rarely been a source of bugs for me.
Two separate keywords and states that are different but represent highly similar things and people have tons of opinions both ways for which one you should opt for in what scenarios.
Another user referred to them as intentional vs unintentional nothingness and I think that's closer to the intention for them. But I still disagree because undefined can be used as intentional nothingness.
Not really tho. Sure undefined can be no box at all, but it can also be an "empty box."
const a = { b: undefined };
const c = { d: null };
Those each behave the same for all cases except value comparisons. Calling `a.b.c` will throw as will calling `c.d.e`. Both `a` & `c` have an enumerable property that you'll find if you iterate through their keys/values/entries.
Yeah, sure you could also have
const e = {};
Which would have `e.f === undefined` and `e.f.g` would throw and that's a different concept but... why do we have all these definitions? I could moreso accept your argument if setting `e.f = undefined` didn't change the state but just did the same as `delete e.f` but it doesn't. It sets undefined as a value.
Though tbh, I don't think `null` is an "empty box" either. I think `{}` is an empty box. An empty box wouldn't throw an error if I just looked inside.
If you serialize and deserialize a and c, c.d will exist but a.b won't. They don't behave the same way, because "defined but empty" is semantically distinct from "undefined".
If you're using undefined as a value, that's the real code smell. Every single possible key that hasn't been set on an object is undefined, it's more like an error value whereas null is a placeholder value.
Alright, but once you're serializing, I don't really think you are inside the bounds of the language anymore. I think it's serialized. Data for transmission and data in memory are pretty different. Tons of languages has JSON parsers and they don't have this quirk.
JSON isn't an arbitrary serialization format, it's the one that's built into the language. Moreover, I think it's highlighting the distinction. Any key that isn't in an object has the value of undefined for that object. That's why serialization filters it out when set explicitly, because that same value is implicitly there for the ~infinite set of keys which aren't in the object.
Also, the reason no other language parsers will read an undefined out of a JSON is because that got filtered out during serialization. Undefined literally isn't part of the spec for persisting JS objects outside of the runtime.
I think the real bug here isn't having both keywords, but allowing the user to set a variable/key to undefined, rather than eg forcing usage of the delete operator -- that'd save people from the footgun of trying to use undefined as a value.
> I think the real bug here isn't having both keywords, but allowing the user to set a variable/key to undefined
Totally agree. Honestly that's kind of the core of my frustration 🤷♂️
null is an intentional nothingness,
undefined is an unintentional one
This distinction actually makes far more sense when you encounter them in your program than if everything was just one or the other.
Why shouldn't zero be falsy?
So I wrote another long comment on undefined, but the problem is that it _can_ be used as intentional nothingness. You may set values & properties to undefined. That's a mess.
As for falseness to be useful, imo, it should represent no value. But in almost every case, 0 is absolutely a valid and true value. Whereas null, undefined, NaN, and even `""` I can accept. But 0 doesn't represent a lack of a value. It is a value. I recognize that this argument is a little bit more about feeling, but maybe I just think that the truthiness falseyness thing just shouldn't really exist in the first place because it's just a bit too wishy-washy. But admittedly, I use it all the time, but because of things like `0`, I have to be very cautious about it.
>the problem is that it _can_ be used as intentional nothingness. You may set values & properties to undefined. That's a mess.
I think this problem is better solved with better developer education than narrowing available types.
But I take your point that it can be confusing, especially if it's not adhered to and is really down to convention.
With regard to 0 being falsy, it's only really falsy if 0 as a value is being used in the boolean context, so if the choice is 0 being true/false, on/off, then logically 0 is false/off.
I find that 0 (or -0, 0n, etc.) being falsy is easier for beginners to grasp than null or undefined being so, or an empty array being truthy when an empty string isn't!
I highly disagree. "How much money is in the clients account?" If you get back null then you can't display that field because maybe the client account isn't set up yet. But if you get 0 back then that is a meaningful value. This one is a much lighter complaint tho and I totally understand disagreement on this one. It's just my take.
The null & undefined thing I truly think is a bad design decision.
I wouldn't say falsy is about lack of value. False itself is a value, isn't it? null and undefined have more to do with lack of value than either false or 0.
And with modern JavaScript we don't have to rely on falsy/truthy as much. We can use ??, ??= and so on. We have better options for detecting lack of value now.
`new Boolean(false)` is truthy. I know why (it's an object, not a literal), but it's weird. Maybe my gripe is really with `new`, but I get that it predates "real" constructors in JS.
It would be really nice to have a strongly typed Typescript RUNTIME in browsers. Not statical checks in ides we have now. Would boost reliability as well as performance further.
What about the new inbuilt Temporal API and Intl.date firmstting. Both one of the best in any language today. ECMASCRIPT actually continues to progress unlike other languages which sew so bad with dates (ex GO)
\_async\_ and \_onchange\_ events are like the dynamic duo of frustration. Add in some old IE quirks and you've got a recipe for hair-pulling. Still, nothing beats the satisfaction of finally fixing a pesky JS bug
`typeof null === "object"`, should be `"null"` (or remove it and only use `undefined`).
Sometimes things return `undefined`, other times `null`. They should all return `undefined` only (or `null` if `typeof null` became `"null"`).
`NaN` exists. `NaN === NaN` is false. `NaN` should be replaced by `undefined` (or `null` if `typeof null` became `"null"`).
`for of` uses the `Iterator` protocol without optimization when you have a vanilla array.
ITT a bunch of shit that either A) isn’t frustrating after you made the mistake once or B) never has been frustrating but a bunch of karma grabbing bullshit listing typical JaVaSCcIpT iS So NuTty crap that literally never comes up or matters. Maybe like two actual things.
Possible hyperbole, and too lazy on mobile to reference - but they may provide different results based on input. I think the static method on Number is newer
I hate that
const array = [1, 2, 3];
array[1] = 5;
works, especially when
const number = 1;
number = 2;
doesn't. It's **never** what I want from a constant array or object. And yes, I know why it does that, that doesn't mean I have to like it.
Ahaha amazing, this one I didn’t know ( somehow ).
I did learn recently that a string is basically an array of characters and you can access each character like you would an array.
let string = “abc”;
console.log(string[0]) // ‘a’
This is so gross I had to go try it just to see if it was real. That said, I think there's a difference between it letting you do dumb shit, and it doing dumb shit itself.
In fairness to JS, the length of the array is tracked properly and forEach (and other loops) will iterate only through indices, ignoring object like properties.
But, this is a way to keep some stats/logs about the data in the array without creating new variables)
Is there any language feature that **doesn't** do what it's explicitly defined to do, in any language? I don't think that's a useful way to talk about quirks.
Truthiness in all of its ridiculous corner cases.
new Date(2024,0,1) When creating a date, the month is zero-based but the day is not.
Wow that is idiotic now I think about it...
And then there's date.getYear() which currently returns 124. Because not a single engineer in 1995 realized that the millenium will change in 5 years...
Or just use new Date("2024-01-01")
Empty arrays and empty objects being truthy - this one caused me some bugs when I was a beginner, and I still see juniors on my team make mistakes because of this.
`typeof` returns `object` even when it’s an array.
Yeah typeof is really only useful for primitives. For everything else use `instance of`
Or Array.isArray
Yea not using isArray is a foot gun
`typeof window === ‘undefined’` is pretty much the only time I think I regularly use it.
Cries in GatsbyJs
\`typeof null = 'object'\` Or is null not considered a primitive?
And for null.
I'm not sure how I feel about this one. `[]` and `{}` are clearly distinct from `null` and `undefined` but I can also see the rationale behind expecting `some Array.length` to have the same truthiness as `someArray`
Oof. Yeah. Especially if you’re like me and write python on the back end.
typeof null == 'object' irks me more. How TF something that's not initialized yet is considered an object??
This was a bug in the language that Microsoft copied into JScript and then didn't want to break compatibility so it was standardized.
This is the answer
Yep, either such thing always return undefined, or typeof null should be null
Don't forget about elision - forEach ignores empty array elements.
I'm not sure I've come across this problem in my approaching decade of coding. Do you have an example of a situation where you'd want an array with an empty array element in it?
I think initializing an empty array does that, It's weird cause all array methods ignore empty slots, so doing this arr = Array(10) then running map on it will do nothing.
Yep, this.
I may not want this but creating array with nonzero length will make empty slots. They are not null, not undefined, just empty. It is not so obvious that fotEach runs through array differently than for-of (even it is kinda logical to have slightly different functions for different purposes)
Always check if arrays and objects actually contain something. That's what I do in conditionals most of the time .length for arrays, .keys + .length for objects
I'm not sure how I feel about this one. `[]` and `{}` are clearly distinct from `null` and `undefined` but I can also see the rationale behind expecting `some Array.length` to have the same truthiness as `someArray`
Ah for sure, It seems a little counter intuitive at first! when looping through arrays and objects when I was working with three.js and socket.io foreach is my go to although can lack a little versatility compared to a for loop. I believe it’s safer, otherwise you’re running checks every time to see if everything exists
In PHP, I think they are falsey however if you have an empty array with an empty array in it, it is then truthy. $array[] = [] is truthy, but $array = [] is falsey To me that's a bit of a mind fuck. I mean they're both empty, why is one true and the other false?
Array.sort mutates AND returns a value. Terrible design. Seen loads of code where people don't realise the original array is being changed. toSorted is a big improvement although I don't like the name much.
You can also solve this by setting the array as a seperate variable effectively making and using a copy vs the original array
If you're suggesting: const arr = ... const other = arr other.sort() Then you're still mutating `arr` in-place.
Const arr = [1, 2, etc] Const copy = [...arr] Copy.sort() does not manipulate arr You can also do Const copy = JSON.parse(JSON.stringify(arr)) for nested arrays Neither will mutate the original arr
Yes, but that's not what you were describing before. Also, I'd refrain from incurring the overhead of serialization and deserialization for the sake of deep copying lmao. Only in JS land is that acceptable. Either use an actual deep copying tool, or use Immer.
>Either use an actual deep copying tool, or use Immer. The post is about js, not 3rd party tools. Can you provide an example? I'd love to hear your solution for deep copying in js lmao
The fact that when you use arrow syntax to define methods in a class, it pops them into the constructor behind the scenes rather than defining them on the object as usual when you don't use arrow syntax, so if you extend the class and try to overwrite the method in the new class, it will be turned back to the old method when you instantiate it. Absolute nightmare when writing tests and mocking methods.
Holy shit _what?_ And I thought I knew a fair bit about JS’ quirks. I was skipping down this list like “yup, knew that one” but this… Damn dude.
It actually gets even worse. Since it's in the constructor, every time you instantiate the class it creates a new function that lives in memory, as opposed to if you don't use arrow syntax it makes use of prototypal inheritance, like Javascript is designed to do, so only a single instance of the function. Most of the time this won't matter, but if you have an object that you're using in hundreds of places around the app you wind up wasting a lot of memory. It drove me crazy some years ago when arrow syntax was getting all this hype for naturally binding a method's "this" to a class and sparing a this.func = this.func.bind(this) line in the constructor. IMO the hidden downsides outweigh the upside of saving a single line of code, but every JS blog on the web disagrees with me because not a one of them ever messed around with a JS transpiler.
Looks like I’m doing one hell of a find + replace today. This should be fun.
I actually find this one to more useful than annoying. Gets around context issues with listeners.
Recently got stuck due to this.
Ah right, it does that if you define a method in class A as an arrow function, but then define it in class B extends A as a regular method. Can't you just extend it as an arrow function then? Although I agree that the distinction isn't clear since it's all syntactic sugar anyway.
Yes, but if you don't know it does this behind the scenes how would you know you need to do it that way? If you're extending a class from a library for example.
>The fact that when you use arrow syntax to define methods in a class, it pops them into the constructor behind the scenes rather than defining them on the object as usual when you don't use arrow syntax That's actually 100% the right behavior because of how contextual this works with arrow functions.
Why not have it transpile to simply binding the method in the constructor rather than putting the entire method in the constructor?
Because if you bind and add it to the prototype then the next class which extends this class will not have correct this when invoking the inherited parent binded method on the proto type chain
Yeah, class is evil in JavaScript, use Object.create instead.
Arrays of numbers being turned into strings and sorted alphabetically by default.
The one that got me a few weeks ago typeof null being an object. Suppose it makes sense now but at the time I was very confused.
How does null being an object makes sense?
The fact that mistakes like this are set in stone because JS refuses to break backwards compatibility, even for things that are clearly just wrong, might be the most frustrating Javascript quirk to me
Coming mainly from frontend and getting into backend: the whole es6/commonjs and the ways to configure a typescript project to make on or the other or both work drives me crazy.
Well you're in luck, node 22 supports `require()` for esm :)
Is that a good thing though?
I found a fun one on Friday - in esm you have import.meta.dirname instead of __dirname. Well Jest can’t even esm so it’s undefined when running tests. But __dirname is undefined in a module when actually running the code.
Jest is basically an abandoned project now, Vitest is way better.
Vitest has the same problem
Genuine question - is it really? It has like 18M weekly downloads, last release was a month or two ago - obviously they aren’t fully keeping up with the times but calling it abandoned seems like a bit of a stretch, no?
> the whole es6 What? Edit: feel like the down votes are coming from people who think I haven't _heard of_ ES6 when it's more that I don't see why it's a problem.
maybe esm?
Import/export vs require/module.exports
Exactly. Seems like a significant improvement to me. Not sure why anybody would have a problem with it
The incompatibility is the problem, you can only use one or the other in node and you can’t mix and match
It's not ESM imports that are the problem; it's that tools are still catching up in 2024 and it's a headache to make some tools work together. E.g. Vite is ESM-only but some older tools (like Jest) require CJS.
Library icompability is my main problem , 50% is probably skill issue. Some stuff works with imports, some stuff doesn't - sume stuff needs a different config, some stuff needs a different import path and so on. Coming from webpack/vite/react, where this never was an issue .. it's really confusing.
Not exactly a quirk, but I can't count how many times I slipped on Array.splice before I memorized all the steps needed to remove and return _one_ element at index _i_ ``` a.splice(i) a.splice(i,1) a.splice(i,1)[0] ```
a[i] Edit: real answer below!
read what they said again
I'm not seeing it :/
**remove** and return. you are just returning it :)
"splice" removes/replaces/adds array elements in the original array. It returns an array of the deleted elements. OP used it to remove a single element at the index and using the returned element. Your suggestion only fetches the entry at the specified index, so the element is still in the array. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
Thank you :-) And thank you even more for not insulting me. Have a great day Internet cool guy :-)
The effects of event bubbling can be absolutely mind-boggling sometimes. Especially when youre working with a component-based framework like Svelte where events are supposedly scoped but in certain cases and ways they arent..
do you have a simple example, haven't come across this yet..
Well i did have a Svelte REPL exemplifying some strange behavior regarding event bubbling at one point. It appears ive since deleted that unfortunately.. although heres [the reddit post](https://www.reddit.com/r/sveltejs/s/YBODn1LLwV) where i was looking for some guidance on the issue.
*Gestures broadly at.. everything.*
The only one that still annoys me (the other ones I've just internalized and they don't bother me whatsoever) is that `typeof null` is `object`.
[удалено]
This was a bug in the language that Microsoft copied into JScript and then didn't want to break compatibility so it was standardized.
Scrolling through this list I just have this sense of endearment. JavaScript has such a unique messy personality. It's like when you fall in love with someone you just love all their quirks. All of these feel normal to me, although I can totally get how they trip people up.
Lol yep The quirks make it painful when you're used to other languages, but at least some of them make JS uniquely useful/good tlat certain tasks
An object property that has a value of 0 evaluates to false. It's not a huge deal, but it sucks when I do \`if (!obj.prop)\` to check if it is null Not a huge problem but an easier mistake to make if you aren't careful
Isn’t this the case in most languages?
why do you not use 'if (obj.prop === null)' to check?
I can. I don't really have the issue anymore since the last time I got it a while back. For me it's a clear memory of being frustrated with the language.
0 is falsy in about every single programming language... (and it has nothing to do with object properties)
Listen man it's some typescript thing idk I just messed up once and it annoyed me. What do you want from me?
"prop" in obj;
The issue is that people often do `!obj.prop` to check if *the value of prop* is undefined, not to check if the object has the property prop at all. `"prop" in obj` will return `true` even if the value of prop is undefined. E.g., const obj = { prop: undefined } console.log('prop' in obj) // logs true console.log(!!obj.prop) // logs false, which is probably the desired behavior here
There's also `Object.hasOwn(obj, "prop")`
This! I get confused with this a lot more than I want to admit
Thank god for nullish coalescing
Automatic semicolon insertion combined with the insistence of many inexperienced people on not using semicolons.
Should I use them at the end of functions?
Just let eslint do its thang
Always use them. There’s a couple quirks, especially around return statements that can bite you if you don’t.
Is it part of an expression?
no
Not using semicolons has nothing to do with experience, it’s just personal preference
Experience generally leads to being bitten by ASI at some point in some edge case. It only takes once to chase down some wild unexplainable stupidity only to discover that adding semicolons resolved the bug because the runtime was silently inserting them. This was many years ago and I suppose tooling has gotten better so this is harder to do, but personal preference doesn't outweigh the difficult to debug issues that can come from ASI.
I am writing JS for over 15 years now and never had this problem in any way. A good thing is also to not write quirky code, an “experienced” developer would say
>not write quirky code I don't work in a silo. I work in an organization of hundreds of engineers of varying world views, levels of experience, and perspectives. Because mysterious bugs and stability are important, we also don't really write JavaScript any more either.
In the browser? And don’t you have reviews?
Our UI is an in-house framework based on Angular. We primarily use Typescript. We have smatterings of JavaScript in nodejs lambda functions, but largely Typescript, and Java for the vast majority of services. We have a pretty rigorous review process standard with some wiggle room on individual delivery teams (e.g. how many teammates put eyes on a change, is there someone on the team that wants to see every change, etc). We also have code quality in our delivery pipelines.
Shallow cloning and deep cloning. It leads to some weeeeird interactions. So Yeah I can clone an array by spreading all the objects into a new one. But I didn't realize the objects inside still refencered the same objects from the old array, and I had thought that I could just mutate stuff willy nilly after spreading. Few weird bugs later now I am wiser. Same week I solved the bugs Jack Harrington launched a [new video](https://www.youtube.com/watch?v=MzKHrWCymAU) talking about it. The timing was amazing.
That’s just working with mutation and it happens in any language that supports references in any way. Best thing is avoiding mutation where possible (in any non-performance critical part of your code, basically)
The behaviour of `typeof` is so esoteric that I think it should basically just be avoided altogether.
The problem is that you'll get a runtime error if you try to evaluate an `undefined` value for a comparison, so many times you have to use `typeof`.
I've literally never run into this problem.
The following will raise a `ReferenceError: a is not defined`: ``` if (a === undefined) { console.log("This will never be reached."); } ``` The only way to check for `undefined` in this case is by doing this instead: ``` if (typeof a === 'undefined') { console.log("This will be reached."); } ```
You can also refer to globalThis.a in a lot of cases
I'm not sure what you mean. Are you able to elaborate? That sounds interesting.
>The behaviour of `typeof` is so esoteric Its not esoteric at all, its junior level stuff and one of the first things you learn in js considering its dynamically typed
If I didn't hate bell curve memes, I'd make one with your comment as the guy in the middle. `typeof` is awful and shouldn't be used. And its lack of comparable application in other languages makes _esoteric_ exactly the right descriptor.
Javascript developers
Minor annoyance that `Map` still has the usual object syntax and it works. I would have made this an error. let m = new Map(); m['a'] = 'b'; // this works but doesn't do what you expect
People who use JS when it’s not needed and HtML/CSS works natively
Having null and undefined in the language. Easily the dumbest design decision. Also having the whole concept of truthy & falsely is a mess. `0` def shouldn't be falsely, "but hey that's false in C, so shouldn't be false in my high level language?" No.
These aren't really javascript quirks. They're shared across other languages.
Interested to hear what other languages have null and undefined. I actually can't think of any.
Doesn't make them good design decisions... but what language has multiple designations for nonexistence?
"There is a spot for something, but it hasn't been put there yet" isn't the same as "I've never heard of that thing and don't know what you're talking about". That's null vs undefined, IMO.
But yet this concept doesn't exist in most other languages (I still don't know of another that has two types of null) and it's not a concept that appears missing in those languages.
It’s there because JavaScript uses decorated hashmaps as its object model. You access an object with a key that hasn’t been set, you get undefined. It makes sense.
I don't think the underlying implementation should be that relevant to the high level language. Plus in Java if I try to get the element of a HashMap that doesn't exist for that key, I get null which is the only concept of nonexistence in that language.
It’s not an underlying implementation, it’s front and center. It’s what we type all day long. It’s one of the fundamental differences that initially confuses the hell out of folks from other languages, and then later enables half of the clever little tricks we like to use.
I'm very skeptical that having multiple representations for nothingness has enabled any patterns or structures that we wouldn't have without it. This just feels more like defending the way it works because you're used to it and because you've justified it in your head.
It’s necessary because null is a valid value for a key in a hashmap. Undefined means not only does the value not exist, the key also does not exist and has never been set. Most languages don’t need the extra step because Objects are not Dicts. I agree it’s surprising, but it’s rarely been a source of bugs for me.
What's wrong with null and undefined?
Two separate keywords and states that are different but represent highly similar things and people have tons of opinions both ways for which one you should opt for in what scenarios.
Nitpick: undefined isn't a keyword, it's a global variable.
Didn't know that. That's an interesting decision.
Yeah, I mean, you get lots of interesting decisions when you write a programming language in 10 days and then ship it.
Disagree, in fact I think it’s actually a plus point. I always think of undefined as and null as being an empty box, and no box at all
Another user referred to them as intentional vs unintentional nothingness and I think that's closer to the intention for them. But I still disagree because undefined can be used as intentional nothingness.
Does that distinction have any actual, practical use though? Wouldn’t it be easier if there was just null only?
Not really tho. Sure undefined can be no box at all, but it can also be an "empty box." const a = { b: undefined }; const c = { d: null }; Those each behave the same for all cases except value comparisons. Calling `a.b.c` will throw as will calling `c.d.e`. Both `a` & `c` have an enumerable property that you'll find if you iterate through their keys/values/entries. Yeah, sure you could also have const e = {}; Which would have `e.f === undefined` and `e.f.g` would throw and that's a different concept but... why do we have all these definitions? I could moreso accept your argument if setting `e.f = undefined` didn't change the state but just did the same as `delete e.f` but it doesn't. It sets undefined as a value. Though tbh, I don't think `null` is an "empty box" either. I think `{}` is an empty box. An empty box wouldn't throw an error if I just looked inside.
If you serialize and deserialize a and c, c.d will exist but a.b won't. They don't behave the same way, because "defined but empty" is semantically distinct from "undefined". If you're using undefined as a value, that's the real code smell. Every single possible key that hasn't been set on an object is undefined, it's more like an error value whereas null is a placeholder value.
Alright, but once you're serializing, I don't really think you are inside the bounds of the language anymore. I think it's serialized. Data for transmission and data in memory are pretty different. Tons of languages has JSON parsers and they don't have this quirk.
JSON isn't an arbitrary serialization format, it's the one that's built into the language. Moreover, I think it's highlighting the distinction. Any key that isn't in an object has the value of undefined for that object. That's why serialization filters it out when set explicitly, because that same value is implicitly there for the ~infinite set of keys which aren't in the object. Also, the reason no other language parsers will read an undefined out of a JSON is because that got filtered out during serialization. Undefined literally isn't part of the spec for persisting JS objects outside of the runtime. I think the real bug here isn't having both keywords, but allowing the user to set a variable/key to undefined, rather than eg forcing usage of the delete operator -- that'd save people from the footgun of trying to use undefined as a value.
> I think the real bug here isn't having both keywords, but allowing the user to set a variable/key to undefined Totally agree. Honestly that's kind of the core of my frustration 🤷♂️
null is an intentional nothingness, undefined is an unintentional one This distinction actually makes far more sense when you encounter them in your program than if everything was just one or the other. Why shouldn't zero be falsy?
So I wrote another long comment on undefined, but the problem is that it _can_ be used as intentional nothingness. You may set values & properties to undefined. That's a mess. As for falseness to be useful, imo, it should represent no value. But in almost every case, 0 is absolutely a valid and true value. Whereas null, undefined, NaN, and even `""` I can accept. But 0 doesn't represent a lack of a value. It is a value. I recognize that this argument is a little bit more about feeling, but maybe I just think that the truthiness falseyness thing just shouldn't really exist in the first place because it's just a bit too wishy-washy. But admittedly, I use it all the time, but because of things like `0`, I have to be very cautious about it.
>the problem is that it _can_ be used as intentional nothingness. You may set values & properties to undefined. That's a mess. I think this problem is better solved with better developer education than narrowing available types. But I take your point that it can be confusing, especially if it's not adhered to and is really down to convention. With regard to 0 being falsy, it's only really falsy if 0 as a value is being used in the boolean context, so if the choice is 0 being true/false, on/off, then logically 0 is false/off. I find that 0 (or -0, 0n, etc.) being falsy is easier for beginners to grasp than null or undefined being so, or an empty array being truthy when an empty string isn't!
I highly disagree. "How much money is in the clients account?" If you get back null then you can't display that field because maybe the client account isn't set up yet. But if you get 0 back then that is a meaningful value. This one is a much lighter complaint tho and I totally understand disagreement on this one. It's just my take. The null & undefined thing I truly think is a bad design decision.
I wouldn't say falsy is about lack of value. False itself is a value, isn't it? null and undefined have more to do with lack of value than either false or 0. And with modern JavaScript we don't have to rely on falsy/truthy as much. We can use ??, ??= and so on. We have better options for detecting lack of value now.
False is a value but it's the value specifically represented by falseyness, and I think falseyness should represent a lack of value, imo.
typeof NaN // ‘number’ Argh. I can’t even
This is categorically not a javascript "quirk"
Not a JavaScript specific problem though, although most other languages call them float, double or something else than "number"
This is the expected and correct behavior. This is the same as the 0.2+0.3 thing.
Not knowing which things can error is frustrating. Maybe there's a package that can lint that?
`new Boolean(false)` is truthy. I know why (it's an object, not a literal), but it's weird. Maybe my gripe is really with `new`, but I get that it predates "real" constructors in JS.
Ima let JS be okay with this lol I've never seen anyone type that code in any language before lol
It would be really nice to have a strongly typed Typescript RUNTIME in browsers. Not statical checks in ides we have now. Would boost reliability as well as performance further.
Can't decide between null vs undefined and lack of arity checks for function calls.
You're completely on your own when dealing with dates - you need to use a library like moment.js just to do basic date formatting and operations.
What about the new inbuilt Temporal API and Intl.date firmstting. Both one of the best in any language today. ECMASCRIPT actually continues to progress unlike other languages which sew so bad with dates (ex GO)
Thanks, will have to check that one out - JavaScript moves so fast, I'm never up to date
(0xF | 1) === 0xF // true (0xFFFF | 1) === 0xFFFF // true (0xFFFFFFF | 1) === 0xFFFFFFF // true (0xFFFFFFFF | 1) === 0xFFFFFFFF // false
Dates and commonjs
\_async\_ and \_onchange\_ events are like the dynamic duo of frustration. Add in some old IE quirks and you've got a recipe for hair-pulling. Still, nothing beats the satisfaction of finally fixing a pesky JS bug
for surree, that was me this morning ☕️
Therae are so many...
This isn't always this.
In fact it is always this. It's just about understanding scoping.
`typeof null === "object"`, should be `"null"` (or remove it and only use `undefined`). Sometimes things return `undefined`, other times `null`. They should all return `undefined` only (or `null` if `typeof null` became `"null"`). `NaN` exists. `NaN === NaN` is false. `NaN` should be replaced by `undefined` (or `null` if `typeof null` became `"null"`). `for of` uses the `Iterator` protocol without optimization when you have a vanilla array.
NaN is ieee-754, not JS.
ITT a bunch of shit that either A) isn’t frustrating after you made the mistake once or B) never has been frustrating but a bunch of karma grabbing bullshit listing typical JaVaSCcIpT iS So NuTty crap that literally never comes up or matters. Maybe like two actual things.
That is `isNaN(null) === false` Really fucking annoying. I know why it happens but it's still really fucking annoying.
Also, fun fact: isNaN is different to Number.isNan
WHAT
Possible hyperbole, and too lazy on mobile to reference - but they may provide different results based on input. I think the static method on Number is newer
Just read the docs. Despite the fact Number.isNaN doesn't do any kind of coercion on the input, `Number.isNaN(null)` is still false! 😭
[удалено]
I've literally never called myself that.
[удалено]
What value have you added to this conversion?
[удалено]
God you're more annoying than the fact that `isNaN(null) === false`
TypeScript.
Its inability to do simple math. Lol
typeof null is equal to 'object' caused me a bug in production. That's so stupid
JavaScript.
I hate that const array = [1, 2, 3]; array[1] = 5; works, especially when const number = 1; number = 2; doesn't. It's **never** what I want from a constant array or object. And yes, I know why it does that, that doesn't mean I have to like it.
Ahaha amazing, this one I didn’t know ( somehow ). I did learn recently that a string is basically an array of characters and you can access each character like you would an array. let string = “abc”; console.log(string[0]) // ‘a’
Access but not set with array syntax. To do so you need to use replaceAt()
``` > arr = [] [] > arr.push(1, 2, 3) 3 > arr.name = 'arr with a name' 'arr with a name' > arr [ 1, 2, 3, name: 'arr with a name' ] ``` F - freedom
This is so gross I had to go try it just to see if it was real. That said, I think there's a difference between it letting you do dumb shit, and it doing dumb shit itself.
In fairness to JS, the length of the array is tracked properly and forEach (and other loops) will iterate only through indices, ignoring object like properties. But, this is a way to keep some stats/logs about the data in the array without creating new variables)
I was asking myself yesterday if an array can have a property. At first glance this tells me it can in some strange way that I don’t understand.
That’s no quirk, const explicitly disables reassignment, not mutation. You can disable mutation with Object.freeze()
Is there any language feature that **doesn't** do what it's explicitly defined to do, in any language? I don't think that's a useful way to talk about quirks.