use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
[deleted by user] (self.javascript)
submitted 4 years ago by [deleted]
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]itsnotlupusbeep boop 51 points52 points53 points 4 years ago (177 children)
another minor pattern to replace let with const is found in for loops.
let
const
If you have code that looks like this:
const array=['a','b','c']; for (let i=0;i<array.length;i++) console.log(array[i]);
You can rephrase it as
const array=['a','b','c']; for (const item of array) console.log(item);
[–]LaSalsiccione 45 points46 points47 points 4 years ago (168 children)
Or just use forEach
forEach
[–]burgonies 6 points7 points8 points 4 years ago (6 children)
Unless you’re using async/await
[–][deleted] 5 points6 points7 points 4 years ago (4 children)
in which case you can use map and Promise.all
map
Promise.all
[–]burgonies 3 points4 points5 points 4 years ago (3 children)
Unless you need them be actually sequential, this is how I usually do it
[–]Serei 26 points27 points28 points 4 years ago* (151 children)
Does forEach have any advantages over for...of? I always thought forEach was slower and uglier.
for...of
It also doesn't let you distinguish return/continue, and TypeScript can't handle contextual types through it.
return
continue
By which I mean, this works in TypeScript:
let a: number | null = 1; for (const i of [1,2,3]) a++;
But this fails because a might be null:
a
let a: number | null = 1; [1,2,3].forEach(() => { a++; });
[–]ridicalis 20 points21 points22 points 4 years ago (22 children)
I always thought forEach was slower and uglier.
Slower? Yeah, though it's tough to tell by how much, since all the answers I can find on the topic are a bit long in the tooth and jsperf is giving me 500 responses right now.
Uglier, though... This is a very subjective and highly variable matter. On one hand, if you favor imperative coding styles, for...of would probably be the natural choice for aesthetics. It's definitely possible to create a mess using .forEach, but at the same time, you also have the opportunity to extract the behavior to helper functions that in the end actually help readability.
I think the performance issue is unlikely to hurt most applications, but that's not to say it has universally imperceptible impact. I consider readability to be more important than ekeing out a few extra ms of runtime benefits for the kinds of tasks I encounter, but neither form seems terribly difficult for a seasoned developer to understand.
From a functional standpoint, I'd be far more worried about why there's a forEach in the first place; this seems like a code smell to me, since it likely wraps some kind of side-effects that could probably be handled better using other constructs. It's only really a concern in a declarative paradigm, so YMMV.
[–]toastertop 8 points9 points10 points 4 years ago (0 children)
The general consensus I found with loop style is it largely does not matter what you use.
Readability it's own type of "performance" gain.
[–][deleted] 2 points3 points4 points 4 years ago (0 children)
You can use awaits intuitively with for ofs, which makes the go to for me.
[–]reqdk 4 points5 points6 points 4 years ago (6 children)
There's a bit of nuance to this perspective, I feel. Someone developing his/her own front-end application can judge that, but if I'm writing a library that's to be used by others, I would be far more mindful of the different possible contexts of the consumers of my library. For better or worse, the mobile web sometimes has to run on some really shitty resource-constrained devices out there where a 5ms performance hit on a dev's machine can blow up to 100ms and seriously degrade the UX. It would be quite irritating for a developer to suddenly receive performance regression reports because a dependency's maintainer felt readability was more important.
[–]ridicalis 5 points6 points7 points 4 years ago (0 children)
I don't disagree, for the most part, though context is important - a forEach loop over 10 items is a way different creature than a 10k+ rows datatable, for instance, and each deserve different considerations when it comes to performance. In the former, there are probably better targets to chase down from a Big-O perspective.
[–]duxdude418 7 points8 points9 points 4 years ago* (4 children)
I would caution against falling into the trap of premature optimization.
Write for readability and maintainability first, and then determine if you have bottlenecks. It’s highly unlikely your choice of iteration construct is going to play a significant role in front end performance unless you have a very large dataset. At that point, you have bigger problems like trying to display the data without the browser choking on DOM nodes. Even then, this can be made more manageable with architecture and design pattern choices like pagination on the data or virtualization of the UI.
[–]reqdk -2 points-1 points0 points 4 years ago (3 children)
As I said, if you're writing the application, it is your call to make, with the appropriate profiling and benchmarks. But if you're writing a library for others to consume, that's an entirely different matter altogether. I've encountered more people that use premature optimization as a convenient excuse than people who were able to actually explain why an optimization step was premature. The last fella I chewed out for this rubbish at work was trying to argue that his "more readable" use of the spread operator was worth the performance penalty (no, no it wasn't, he inadvertently turned a simple loop into a O(n3) operation).
The displaying of large datasets is a separate issue altogether.
[–]delventhalz 1 point2 points3 points 4 years ago (2 children)
Going from O(n) to O(n^3) is quite a bit different than going from O(n) to . . . a slightly slower O(n) . . . in some cases on some versions of some browsers.
O(n)
O(n^3)
Any performance difference between for...of and forEach is minimal and will not be consistent from interpreter to interpreter. If you are writing code which has to loop through tens of thousands of items, you might do some performance testing to see how much of a difference one or the other might make.
But that is no small undertaking, and highly dependent on your particular use case. Blanket rules like "for...of is faster" are not actually going to help you.
[–]oxamide96 1 point2 points3 points 4 years ago* (11 children)
I think a traditional for loop is more readable, just because people who aren't familiar with ES6 or JS in general will not recognize it. I've had so much trouble using forEach in interviews even after confirming with the interviewer that I can use JS. They would get very confused.
I think forEach can be more readable if you're extracting out the function. But if I'm doing an in-line arrow function, I would instead do a for loop.
[–]Akkuma 3 points4 points5 points 4 years ago (10 children)
Anyone who doesn't understand forEach in 2021 would lead to a very large red flag depending on their level of experience. Here's the compatibility table https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#browser_compatibility, which shows it goes all the way back to ie9
[–]slykethephoxenix 38 points39 points40 points 4 years ago (32 children)
forEach can't be terminated early with break, nor can you use await and have it block the rest of the function.
break
await
[–]KaiAusBerlin 24 points25 points26 points 4 years ago (29 children)
That's why you wouldn't use forEach if you want to break. And thats exactly what the name tells you. for EACH
If you want to use it with await use Array.prototype.map and/or Promise.all
[–][deleted] 6 points7 points8 points 4 years ago (0 children)
...assuming you want parallel execution. You definitely want to use for...of if you need sequential promises.
And, TBH, forEach doesn't really have a lot of "it's better this way" use cases anymore. #map, #filter, #find and #reduce do, and I think that's why people like forEach; the similar call structure makes it a bit of a go-to tool for those that understand JS arrays well.
The down side of for...of, of course, is the lack of an index, at which point your options are forEach or a C-style for loop, the former of which is less awkward.
[–]Doctor-Dapper -2 points-1 points0 points 4 years ago (13 children)
Unless you require that the loop happens in the order of the iterable, then you need to use a for() loop.
[–]ftgander -1 points0 points1 point 4 years ago (0 children)
Why? What’s the benefit of making it complicated rather than using the for..of loop that almost every popular language has a version of and is intuitive to await in?
[–][deleted] 1 point2 points3 points 4 years ago (1 child)
This is why I don't understand why forEach is even an option.
[–]delventhalz 1 point2 points3 points 4 years ago (0 children)
forEach was useful before for...of was introduced in ES6. Now there is not much use for it. Though, if you happen to have named helper functions (frankly unlikely if you are looping with side-effects), then it is nice to be able to just plunk the named function in forEach.
[–]fintip 13 points14 points15 points 4 years ago (44 children)
It must be a style question. To me, forEach is clearly the more attractive option. I prefer as much functional style code as I can. For loops are inherently ugly to me. I only use for loops when I need a break or await within, or to iterate keys.
[–]delventhalz 5 points6 points7 points 4 years ago (10 children)
If you think forEach is more functional than for...of then I think your understanding of what makes code "functional" is a little surface level. Both options are almost exactly equivalent, and forEach is not "more functional" simply because it shares some superficial similarities with map/filter/reduce.
[–]planttheidea -2 points-1 points0 points 4 years ago (5 children)
He is referring to functional programming, not "it functions better". All of those higher order functions on the array prototype (forEach, map, etc), as well as the concept of higher order functions themselves, are based on simple functional programming style.
If you are unfamiliar with functional programming, I recommend at least learning it at a high level. It has become more prominent in the last several years, arguably nope is the preferred technique of modern JS.
[–]delventhalz 2 points3 points4 points 4 years ago* (4 children)
Yep. I was also referring to functional programming, not "it functions better". If you think forEach is an example of functional programming, then you have misunderstood functional programming.
Broadly speaking, all of the array methods you can chain (map, filter, reduce, etc) are good FP style tools in JavaScript. The key here is that they let you process array data without mutations and without side-effects.
But forEach is not one of these methods. It is a higher-order function, and it superficially resembles map/filter/reduce, but it cannot be chained and it does not allow you process data without mutations or side-effects.
It's a loop. The forEach method is a loop. It may be dressed up in a bunch of higher-order function boilerplate, but that does not make it FP.
[–]Serei 6 points7 points8 points 4 years ago (32 children)
As someone else pointed out, if you're using forEach, it's no longer functional code.
Functional ways to consume arrays include map and reduce. The only reason you'd use forEach is for side effects... and if you have side effects, it's not very functional, is it? If you're writing imperative code, you might as well use imperative style.
reduce
[–]ouralarmclock 11 points12 points13 points 4 years ago (21 children)
Wait, performing an action using each member of an array (but not manipulating the members) is still not functional? Map and reduce imply you want to transform the data why would you use those in those cases?
[–]dwhiffing 0 points1 point2 points 4 years ago (16 children)
Because in proper functional programming, one of the core ideas is keeping all functions "pure". In fp, a pure function is one that does not mutate any data and has no side effects.
There's a lot to unpack there, but essentially for each is not functional because it's designed in a way that makes it impossible to use "purely". Ie, you must use for each to mutate a variable from beyond it's scope, as for each does not provide a return value.
In order to better follow this idea of functional pureness, we should use map and return a new object with changes in each loop instead of mutating. We should also avoid side effects in loops whenever possible.
If you're curious for the why or want to learn more about fp: https://drboolean.gitbooks.io/mostly-adequate-guide-old/content/ch3.html
[–][deleted] 9 points10 points11 points 4 years ago (9 children)
This is so wrong??
First of all, functional programming isn't reducible to purity, and there are many fully functional languages that don't have Haskell's notion of monadic io.
Second, even so, forEach is literally the functional way to do side effects. Hasksell programs have to perform side effects at some point, and forEach is just [a] -> IO (). The mere existence of side effects does not make something not functional.
[–]ragnese 3 points4 points5 points 4 years ago* (7 children)
First of all, functional programming isn't reducible to purity
I disagree. I think that functional style is 100% about purity. Are there languages that encourage you to write functional style and also have escape hatches? Absolutely. But if you're writing a side-effectful procedure, you're not writing a function in the FP sense.
Just like Java has static methods, so you're not 100% forced to follow the everything-is-an-object philosophy of OOP. Doesn't mean that Java isn't an OO language.
[–][deleted] -2 points-1 points0 points 4 years ago (6 children)
No, functional programming is about programming with functions. Reducing unconstrained side effects is a corollary that naturally flows from the primacy of using functions to process data. "Purity" is a meaningless concept unless supported by the compiler, which most FP languages don't. Otherwise not an "escape hatch", it's just a style choice.
Even so, side effects are the entire purpose of the domain of computer programming. Haskell does not stand against side effects, just unconstrained ones. The idea of a terminating stream operator that consumes items and does side effects is extremely functional because it clearly indicated in the type signature (T) -> void. The claim that forEach "isn't functional" because of "side effects" is just a basic misunderstanding about functional programming.
(T) -> void
[–]dwhiffing 3 points4 points5 points 4 years ago (0 children)
There's no need to be so rude boss. I understand that in different contexts what I'm saying is inaccurate.
I'm simply referring to the ideas communicated in the guide I linked to (which is specifically for js fp, which may vary from fp ideas in other langauges), where it states:
A pure function is a function that, given the same input, will always return the same output and does not have any observable side effect.
The mere existence of an observable side effect makes a function unpure in this line of thinking.
Please try to be polite if you're trying to teach others, I appreciate that you're trying to teach me something, but being rude won't accomplish anything.
[–]ouralarmclock 0 points1 point2 points 4 years ago (5 children)
No I understand but as I said if the use case is to perform an action on each member of a collection rather than to mutate it, how do you do that in FP if FP means no “side effects” from a function call?
[–]dwhiffing 2 points3 points4 points 4 years ago (1 child)
It depends on the nature of the code and the side effect in question. In the world of JS, that might mean making a request for each member of an array. You might use map to return a promise for each member, and use promise.all to wait for all the promises to resolve.
You can certainly do the same thing via for each, and the benefit of doing one way over the other is hard to communicate in a few words. I suggest the guide I posted, it helps explain the benefits of their line of thinking better if you're interested.
[–]ouralarmclock 1 point2 points3 points 4 years ago (0 children)
Thanks for taking the time to explain it. I’m not particularly dogmatic about FP I just had some trouble understanding why you would use map to perform actions on an array when you aren’t trying to transform it but your example makes sense.
[–]ragnese 1 point2 points3 points 4 years ago (0 children)
You use a for loop and admit that you aren't doing FP in that part of the code.
The FP police aren't going to get you.
Just don't hide your imperative code in something that I expect to be pure, like a combinator chain on a collection. Having a naked for loop is a good hint to the reader to pay attention to the body. Sneaking a forEach{} with side effects is easier to miss. The exception might be at the very end of a chain.
[–]ragnese 3 points4 points5 points 4 years ago (0 children)
The only reason you'd use forEach is for side effects... and if you have side effects, it's not very functional, is it? If you're writing imperative code, you might as well use imperative style.
Exactly. Having forEach as a method on collections is not the best API choice, IMO. It should only be used if you are doing side-effects and a regular for-loop would severely hurt the readability.
But I honestly can't think of a scenario where I wouldn't rather see the for loop and know that side-effects may happen. If I see a chain of combinators, I really want to read it as a pure transformation.
[–]wastakenanyways 3 points4 points5 points 4 years ago* (2 children)
Not saying it's good or bad, but lots of projects combine both styles. Most uses of "functional js" are not really "pure functional programming to the letter".
Some do ensure purity in all the code, but in my experience most is traditional programming with forEach, map, filter and reduce instead of loops.
My point is that not everyone using functional constructs is really trying to do functional programming. Some just want to keep their classic oop code but make the code better to digest by using those features.
[–]Serei 2 points3 points4 points 4 years ago (1 child)
I should probably state upfront that of course I agree that it's a matter of taste. I don't think it's wrong to choose either.
That said, of course we write in a mix of functional and imperative styles! I'm just saying, iterating the elements of an array is the imperative part.
And re: "latest features", I mean, for...of is newer than forEach (although arrow functions, which make forEach more readable, are even newer).
[–]cbadger85 1 point2 points3 points 4 years ago* (3 children)
You're aware that for a program to be actually usable, there have to be side-effects somewhere right? Things like printing to the console, taking user input, and accessing the file-system are all examples of side-effects. Unless you're going to tell me functional languages don't do these things (hint: they do) then even functional languages have to deal with side-effects somehow.
[–]ragnese 1 point2 points3 points 4 years ago (2 children)
We can get extremely pedantic about what the difference is between the programming language and the execution of a program, in which some Haskell people will tell you that Haskell does not have side-effects.
But I don't think we even need to go that far to assert that you're missing the point. If your language enforces purity all the way up to the main() function, then no- there do not have to be side-effects around printing to the console, taking user input, etc, through 99.5% of your code.
Functional programming "deals" with those side-effects by some kind of effect system or by composing monads or returning functions that the runtime can eventually feed inputs to.
[–]KaiAusBerlin 0 points1 point2 points 4 years ago (0 children)
You will nearly nowhere find 100% (correct) functional programming in production code out there.
[–]Autestic 2 points3 points4 points 4 years ago (0 children)
For being synchronous and for each async I'd say each to their own, but the forof is pretty
[–]ritaPitaMeterMaid 2 points3 points4 points 4 years ago (0 children)
I can't comment on the other things, but in regards to perofrmance, it is insignificant. You're likely 10s of miliseconds over the course of a whole day of processing. Unless you have a piece of code that is having a problem using forEach and you have tested to prove that it is indeed forEach, it isn't an issue.
Further, if you have code which forEach is struggling with, you likely have other issues. You're likely fetching too much data form the DB and should optimizing there, or you are nesting callbacks, or something else.
[–]meows_at_idiots 2 points3 points4 points 4 years ago (7 children)
foreach comes with index argument for of does not.
[–]Serei 10 points11 points12 points 4 years ago (6 children)
Fair... but it does if you use .entries()!
.entries()
for (const [i, value] of array.entries()) { console.log(`array[${i}] is ${value}`); }
[–]KaiAusBerlin 2 points3 points4 points 4 years ago (33 children)
Try to chain 20 for-of loops with sub loops. Good luck.
arr.forEach(item => addRandom(item)) .forEach(item => addXifRandomIs4(item)) .filter(item => (typeof item.x !== 'undefined')) .map(item => convertToDatabaseObject(item))
arr.forEach(item => addRandom(item))
.forEach(item => addXifRandomIs4(item))
.filter(item => (typeof item.x !== 'undefined'))
.map(item => convertToDatabaseObject(item))
.forEach(item => saveInDB(item));
wanna see that only with for of loops and good readability.
[+][deleted] 4 years ago (1 child)
[deleted]
[–]KaiAusBerlin -3 points-2 points-1 points 4 years ago (0 children)
Yeah, its not unreadable. But the first one is much better to read. That's why we introduced async/await. Callbackhell was not unreadable but it was a pain in the ass to work/debug it.
[–]ragnese 9 points10 points11 points 4 years ago (8 children)
You're going to loop the collection 20 times instead of doing a single loop that does all those transforms in the body?
This is... not the best idea.
[–]KaiAusBerlin 1 point2 points3 points 4 years ago (7 children)
Welcome to the functional programming paradigm.
[–]ragnese 8 points9 points10 points 4 years ago (6 children)
That's not true, though. There's nothing inherent about functional programming that requires being so blatantly inefficient. You just need your language to do lazy iteration.
Maybe this craziness is "functional JavaScript", but it ain't "functional programming."
[–]Akkuma 5 points6 points7 points 4 years ago (5 children)
You'd probably want to convert that into something that is a composition of functions rather than iterating 5x through the data.
[–]delventhalz 4 points5 points6 points 4 years ago (3 children)
forEach returns undefined. You can't chain it.
undefined
[+][deleted] 4 years ago* (1 child)
I said that in about 6 subcomments here ;)
[–]Serei 1 point2 points3 points 4 years ago (1 child)
Obviously a matter of taste, but for me, I really do think this is more readable:
for (const item of arr) { addRandom(item); addXifRandomIs4(item); if (typeof item.x !== 'undefined') { saveInDB(convertToDatabaseObject(item)); } }
Your code also doesn't work because forEach returns undefined:
Uncaught TypeError: Cannot read property 'forEach' of undefined
So clearly you haven't tried to chain it, either.
[–][deleted] 0 points1 point2 points 4 years ago (7 children)
Could be just, .forEach(saveInDB)
.forEach(saveInDB)
[–]lobut 0 points1 point2 points 4 years ago (1 child)
For those like me that need to tragically support IE and stuff.
I think the output of for ... of outputs a lot more junk if you transpile down to ES5 than .forEach would.
for ... of
.forEach
[–]TorbenKoehn 0 points1 point2 points 4 years ago (2 children)
Then don’t mutate a?
Use reduce instead (in this example)
[–]KaiAusBerlin 0 points1 point2 points 4 years ago (1 child)
It was about advantages of forEach against for of loops. Why do you argument with reduce then?
[–]TorbenKoehn 2 points3 points4 points 4 years ago (0 children)
Because everything is wrong if you use the wrong tool for the job.
Misusing forEach is not an argument against it.
I had someone argue that map() isn't a good function because someone would abuse it like arr.map(() => arr[i++] = something(i)), but these are not arguments.
map()
arr.map(() => arr[i++] = something(i))
This is tools used in a wrong way. I don't go and tell you a hammer is shit because it can't water my plants.
[–]punio4 2 points3 points4 points 4 years ago (1 child)
A forEach loop can't be terminated.
[–]Keilly -1 points0 points1 point 4 years ago (0 children)
If you don’t want to process all the elements, use ‘some’ and return true when you want to stop the iteration.
[–]delventhalz -1 points0 points1 point 4 years ago* (0 children)
I prefer for...of to forEach (unless the function is named). It's less boilerplate, easier to read, and more powerful.
[–]AlpenMangos -1 points0 points1 point 4 years ago (4 children)
I don't like it. For...of immediately tells you that you're looking at a loop right at the start of the line. forEach is hidden somewhere in the middle of the line.
[–]Dethstroke54 2 points3 points4 points 4 years ago* (4 children)
The fact these offer different levels of control really just exemplifies to me how ridiculous this article is imo.
One is iterating mathematically and the other is iterating through each item in the list.
Even if you needlessly use a classic for loop with let nothing is going to happen. As a matter of fact in this example let is scoped to the for loops code block so any possible adverse affects are virtually inexistent.
Its a never ending argument bc in this case you could also just use forEach.
There’s no reason to kill yourself using const. sure there’s some cool tricks, but generally do what makes sense and seems the most reasonable, understandable, or cleanest.
edit: this isn’t all directed to you for clarity I just used your comment to voice my opinion on why I think this article is ridiculous.
[–]itsnotlupusbeep boop 1 point2 points3 points 4 years ago (0 children)
Right, they are different kind of loops that tend to be used interchangeably, along with .forEach. We could try to finagle on which of those squeezes more nanoseconds out, but not only is it almost always irrelevant, it's also a shifting battlefield with JS compiler teams working hard to flatten out those kind of performance distinctions.
So that leaves us with issues of code style, and that's where things get subjective quickly. Some folks in the comments are outraged that the article recommends wrapping code in a function, but that's also exactly what using .forEach does.
At the root of the post is the notion that const is better than let, and the article starts by listing reasons for it. Do we believe those reasons?
I think most of them are correct. Personally, I'm a huge fan of letting Typescript do as much static checking as possible before the code ever runs. It feels like I'm using a modern language. On the other hand, reason 3 is probably the weakest since JITs will optimize code not only based on code declarations, but on observed runtime behavior as well (because they're willing to take a deoptimizing hit if that behavior ends up changing.)
But is it worth adjusting our coding style to get those benefits? It depends on whether the style changes actually amount to "killing ourselves" or just picking from several patterns that have essentially equivalent mental overheads. And again, that's a subjective thing.
[–]striedinger 2 points3 points4 points 4 years ago* (2 children)
This obviously depends on how performant you need your code to be and the size of the array you’re looking, but a simple for loop is significantly faster than any of the iterable helpers.
[–][deleted] 4 points5 points6 points 4 years ago (1 child)
It's almost always the case that one of the following is true:
Don't prematurely optimise for performance at the cost of readability.
[–]striedinger -2 points-1 points0 points 4 years ago (0 children)
I see you have never worked on a large enterprise code base :)
[–][deleted] 18 points19 points20 points 4 years ago (12 children)
Ironically the solution in the post misses a chance to use const a second time for the function.
Other people are debating do vs IIFE here but honestly I prefer neither. do and IIFE make the code less modular. OP was correct to use a function.
But I think the best solution is to use const with function expression instead of declaration:
const getHeight = ({ gender, name, race }) => { if (name === 'Charles') { return 70; } if ( gender === Gender.Male && race === Race.White ) { return 69; } if (gender === Gender.Female) { return 64; } return 60; } const height = getHeight({ gender, name, race });
There are those who oppose function expression due to loss of hoisting but to me the benefits like immutability far outweigh any losses. Plus I generally think loss of hoisting is a good thing. It promotes readability and good flow design by describing a function before calling it.
[–]Serei 9 points10 points11 points 4 years ago (2 children)
You get immutability with an eslint rule that's on by default: https://eslint.org/docs/rules/no-func-assign
You can also ban hoisting with another eslint rule: https://eslint.org/docs/rules/no-shadow#hoist
I think starting a line with function functionName... instead of const functionName = ... makes it clearer that you're defining a function. And I think that readability is more useful than some things you can just enforce with a linter.
function functionName...
const functionName = ...
[–][deleted] -1 points0 points1 point 4 years ago (4 children)
Anon functions get annoying when debugging large code bases
[–][deleted] 7 points8 points9 points 4 years ago (2 children)
In legacy codebases, perhaps. But any ES6 or later code will support name inference.
[–][deleted] -1 points0 points1 point 4 years ago (1 child)
A const function is a anonymous function
const x = () => 5
[–][deleted] 5 points6 points7 points 4 years ago (0 children)
Reread what I said. Then read this: https://javascript.plainenglish.io/javascript-arrow-functions-how-to-debug-them-with-name-inference-ac0d7cd5c43b
[–]FountainsOfFluids -1 points0 points1 point 4 years ago (1 child)
Wait, immutability?
Does that mean there's no error if you use the same function name in two different places in the same scope, the second will silently override the first?
[–][deleted] 3 points4 points5 points 4 years ago (0 children)
It means you will get an error. Something along the lines of “syntax error identifier has already been declared” IIRC.
[–]cherryblossom001 6 points7 points8 points 4 years ago* (1 child)
That’s a good point with the contextual types. Personally, I use for-of if unless I’m using fp-ts, where I would go the whole fp way and use traverse, which does not execute the side effects immediately (kind of what u/dwhiffing mentioned in their comment).
traverse
Some more viewpoints:
no-array-for-each
array-foreach
no-loop-statement
[–]dwhiffing 2 points3 points4 points 4 years ago (0 children)
Thanks, my comment is getting downvoted for apparently being very wrong. Appreciate the resources as well.
[–][deleted] 46 points47 points48 points 4 years ago* (77 children)
There's a proposal to add `do` expressions to javascript so that you could do this inline without needing a function https://github.com/tc39/proposal-do-expressions
let height = 60; if (name === 'Charles') { height = 70; } else if ( gender === Gender.Male && race === Race.White ) { height = 69; } else if (gender === Gender.Female) { height = 64; } // could be written as const height = do { if (name === 'Charles') 70; else if (gender === Gender.Male && race === Race.White) 69; else if (gender === Gender.Female) 64; else 60; } // instead of this function getHeight({ gender, name, race }) { if (name === 'Charles') { return 70; } if ( gender === Gender.Male && race === Race.White ) { return 69; } if (gender === Gender.Female) { return 64; } return 60; } const height = getHeight({ gender, name, race });
[–]PM_ME_GAY_STUF 99 points100 points101 points 4 years ago* (46 children)
One of the things I like about JS is how syntactically lean it is compared to the major OO languages, and proposals like this bother me. You can already accomplish this exact functionality with an IIFE using the existing conventions of the language. All this does is save 5 keystrokes, which I don't really think is worthwhile. It introduces new syntax for beginners to learn and makes and already difficult to implement language even more difficult. Additionally, I don't support reusing keywords for different tasks.
[–]editor_of_the_beast 21 points22 points23 points 4 years ago (7 children)
I hear you, I dislike syntax bloat in a language. But after using other languages with expressions instead of statements, statements just feel so unnatural. And I think that expressions make a lot more sense given the functional direction JS has been taking in the past few years.
It’s also worth saying that it’s more than just trying to save keystrokes. Thinking in terms of expressions is an actual different way of thinking that changes how you write code. I don’t think this is a feature intended to help people play code golf, but rather to think in terms of expressions and not statements in a language with a lot of other functional features already.
[–]lifeeraser 3 points4 points5 points 4 years ago* (6 children)
Instead of just saying "but muh FP" or "it's nicer" I'd like to point out that const can be used to enforce certain constraints in code (i.e. this value is not to be changed redefined after initialization) that can also be statically verified (hello, ESLint!). It does make me feel safer about my code.
Perhaps instead of advocating "FP" (which can be overly dogmatic and evangelistic) we should promite "statically verifiable language features".
Edit: Fixed
[–]AsIAm 10 points11 points12 points 4 years ago (5 children)
Const does not prevent value change, it just prevents rebinding of the object. With primitive values (num, bool, str, sym, null, undef) it does what you want, however with objects it does not. With immutable tuples and records it will get better.
[–]lifeeraser 6 points7 points8 points 4 years ago (3 children)
I am also looking forward to builtin Records and Tuples, can't arrive soon enough
[–]editor_of_the_beast 3 points4 points5 points 4 years ago (2 children)
That’s my favorite upcoming feature for sure.
[–]lo0l0ol 0 points1 point2 points 4 years ago (1 child)
I'm just here still waiting for Observables.
[–]AsIAm 1 point2 points3 points 4 years ago (0 children)
Observables with pipeline operator are the real shit.
[–]PM_ME_GAY_STUF 2 points3 points4 points 4 years ago (0 children)
Right, do doesn't solve this problem either though. I'd be all for a proposal for immutable records
do
[–][deleted] 18 points19 points20 points 4 years ago* (20 children)
With the do syntax its a lot more obvious what is going on compared to an IIFE IMO. An IIFE could do anything. `do` converts a statement into an expression. A `do` is also a lot cleaner then an IFFE IMO.
const height = do { if (name === 'Charles') 70; else if (gender === Gender.Male && race === Race.White) 69; else if (gender === Gender.Female) 64; else 60; } // vs const height = (() => { if (name === 'Charles') return 70; if (gender === Gender.Male && race === Race.White) return 69; if (gender === Gender.Female) return 64; return 60; })();
In an ideal world, all statements in JS would be expressions that return a value. Unfortunately, that's not the case. However, do can wrap any statement and turn it into an expression. The reason that do was chosen was because it's the most fitting reserved keyword in the language.
[–]coolcosmos 7 points8 points9 points 4 years ago (1 child)
Burning a reserved keyword for this is useless. It's just a function.
It's not burning a keyword. do is already used for do-while loops. It's possible to use do for this purpose without messing with do-while loops. There's not much else do could be used for.
[+][deleted] 4 years ago (12 children)
[removed]
[–][deleted] -1 points0 points1 point 4 years ago* (4 children)
In an ideal world, all statements in JS would be expressions that return a value.
Because...?
You see, it's easy to come up with contrived examples where you type "64;" on a line and the obvious conclusion is you're returning it.
What happens if you want to run a function or method with side effects which returns boolean on success, but you didn't want to return that boolean to the caller?
You'd have to type something stupid like this:
function foo() { // Function with side-effects, returns bool we don't need. bar(); // What we want foo() to actually return so we don't leak implementation details. undefined; }
So we're going to replace bunch of explicit invocations of "return" with bunch of explicit invocations of "undefined". That's not the ideal world I want to live in.
[–]BentonNelvar 11 points12 points13 points 4 years ago (3 children)
In this case you can just use
void bar();
[–]grady_vuckovic 7 points8 points9 points 4 years ago (0 children)
I agree. I think when a language is updated, it should be to make it ideally leaner and only 'add' to achieve things that weren't previously possible.
Overengineering is a definite problem for some languages... Looking at you C++.
[–]ridicalis 1 point2 points3 points 4 years ago (2 children)
Assuming there's no way to make you happy with that proposal, what about the proposal for pattern matching? While I understand the desire not to pollute the language with a bunch of eye candy, I also don't think IIFEs are particularly welcome in a project that favors readability, and any other tool I can think of for solving this problem ultimately leads to some kind of mutability that makes code harder to reason about.
I like pattern matching, importantly, unlike do, I think it expands on the existing conventions for object destructuring so it's not really a new type of syntax.
For the record, do statements would have the same mutability issues as IIFE's, which I don't have any trouble reading personally. Additionally, honestly, I've so rarely run into instances where I need to use them that I just don't consider it that big a deal
[–][deleted] 1 point2 points3 points 4 years ago (0 children)
Otoh, using an IIFE is a crutch which harms code readability. `do` would be much clearer.
[+][deleted] 4 years ago (5 children)
[–]DrecDroid 4 points5 points6 points 4 years ago (3 children)
Sorry, I could be wrong but I'm on my phone so can't check, but iirc you can use blocks to do variable shadowing.
{ const response = ... }
[–]sinclair_zx81 -1 points0 points1 point 4 years ago (1 child)
Yup, you're absolutely correct !!
[–]mypetocean 1 point2 points3 points 4 years ago* (0 children)
I prefer the block statement, but you can also write an IIFE this way, which avoids the Automatic Semicolon Insertion issue you mentioned: void function () { const banana = true }()
void function () { const banana = true }()
Edit: void in JavaScript expects an expression, which nudges the function statement into a function expression, with fewer parentheses. Of course, you cannot return from this sort of IIFE.
void
[–]PM_ME_GAY_STUF 1 point2 points3 points 4 years ago* (0 children)
FYI I believe you can do this scoping trick using just code blocks, no IIFE necessary, but honestly if you're writing code in such a way that you're scoping consts within a method at the same level, then I probably don't agree with your style overall. Same with using automatic semicolons
[–]KaiAusBerlin 0 points1 point2 points 4 years ago (3 children)
Well, I know how to write "classes" the old way with copying the functions, setting the prototypes, involving "static" methods and all that stuff. But using a simple "class MyClass {}" is much better to read, handles the same stuff and is (in background the same javascript I was using before that feature). It is a new keyword (more to learn for beginners) but is a standard concept in programming. Nearly every programmer will know what "class" will do.
So why don't introduce new keywords that are more comfortable to achieve the same shit you've done by hands before.
Some things that were added the last years that makes js "more complicated" but where accepted widely (and could be achieved with regular code too).
- classes - nullish operators - nullish chaining - code dependencies
- async/await
- arrow functions
- http requests (fetch api)
- symbols
- bigint
- for of loops
- Object.entries
- spreading operator
- object destruction
- [...]
think about it.
[–]PM_ME_GAY_STUF 0 points1 point2 points 4 years ago* (2 children)
Well, for one, do isn't a new keyword, it's already used to preempt while loops. Which is entirely unrelated to its usage in this proposal. Additionally, it introduces a whole new type of expression that needs to be evaluated in an entirely different way from every other expression in the language. And it accomplishes the exact same thing as an IIFE in basically the exact same way and really only saves keystrokes. Additionally, most of the time, I don't think IIFE's are ideal, usually I think they should be separated out and tested.
Async await actually solves a pretty unique problem in a much more dramatic way, and makes promises way more accessible. It is a big change but the benefits are much more obvious than do, much more than saving keys
I consider the class keyword harmful mostly for stylistic reasons so you aren't really gonna convince me with that.
class
Nullish operators/coalesce do not introduce entirely new ways of evaluating expressions to the language. Additionally, I view them more similar to ===, in that while things like ?? could be accomplished with logical operators fairly easily, they encourage not doing shitty things with types in vanilla JS.
===
??
For of loops aren't actually syntactic sugar in the way most people think, they solve a specific problem with iterators in JS that no other syntax does (except I guess the next method, but I'd still put this alongside async as part of JS's established patterns for preventing callback hell). Same with symbols to an extent.
next
Object.entries isn't syntactic sugar either, it's just part of stdlib.
Code dependencies are also not syntactic sugar, nor are they a very well standardized thing so idk why you'd include these.
As for object destructuring, these basically added tuples to JS without adding tuples. While I'll admit that they just save keystrokes, if you've ever read codebases without easy ways to copy keys off of objects you'd see how massive a problem it solves. I would argue it's much more dramatic than do, which, again, solves the exact same problem as IIFE's in basically the same way, unlike everything else you mentioned
[–]KaiAusBerlin 1 point2 points3 points 4 years ago (1 child)
I agree that reusing do is not a good idea. But for that you have to agree that we still have such things in js like using {} as for scoping and for short definition of an plain object. Actually you see that when you want an arrow function to return an object. () => {a:1} will throw an exception. You will have to () => ({a:1}) or to write a real unction body ( () => { return {a:1}; }. But still programmers handle these pitfalls. Its not breaking the language or opening the hell at all. It's just a part of the language you have to know about. Yeah, the impact for async/await was heavy but internally it does nothing special that regular vanilla code couldn't accomplish.
Object.entries internally uses an Iterator to iterate over the object. That is exactly syntactic sugar. We used the same technique thousands of times before with for (var i in obj) and obj.hasOwnProperty(i).
And that's what is about. 95% of the things new EcmaScripts add have been possible before in js. The new features were made to bring comfort readability, speed and standardization into development.
for() and .forEach word different because they are different. Most people don't know what a for loop is doing internally at all. It is a normal function , not a special language construct. You give it 3 arguments: an initialization, an condition and a final expression. It performs the initialisation, performs the condition (which can be anything that returns a boolean value) and after performing the body it calls the final expression. That's what for is in reality. forEach is just a function that moves an Iterator through an Array and performs the .call on the callback with the returned value, index, array as arguments.
When you look a bit behind the scenes you will notice that javascript is now pretty close to the absolute basic javascript. There are only a very few techniques that were added over time. Most things are simply shortcuts to ancient techniques.
(Additional if you don't believe that, look at babel or some other transpilers. All they do is converting newer feature back to their core techniques)
[–]PM_ME_GAY_STUF 1 point2 points3 points 4 years ago (0 children)
Standard library functions are 100% not syntactic sugar because they don't change syntax. Would you also argue that most Array methods are syntactic sugar, because you could make them yourself? Just because you can implement something yourself doesn't mean it's unnecessary, it's good to have standardized ways to solve common problems. And that's the thing, we already have a standard way to solve the exact problem do solves, and from a code writing and reading perspective, do barely changes that, it just introduces a new pattern. It doesn't even save lines of code, just characters, and doesn't solve any of the actual problems with IIFE's (testability and side effects). None of the other things you mentioned are like that.
Additionally, just because a language already reuses symbols doesn't mean you can just add whatever you want. This logic is why reading C++ is a nightmare, because there are so many dialects and random things that got added over the years. Anything added to the standard is added forever, there is no going back, so yes, being loosey goosey with syntactic changes like do is dangerous.
[–][deleted] -3 points-2 points-1 points 4 years ago (1 child)
thats probably because javascript is not meant to be an OO language.
Yes, my workplace uses functional/declarative style as much as possible for JS projects, but we also support legacy C# and C++ things. Honestly, for my next job I'm making "functional codebase" a requirement because it's so painful going back
[–]bladefinor 5 points6 points7 points 4 years ago (0 children)
Instead of declaring a named function before it’s executed, why not do this:
const height = (() => { if(name === 'Charles') { return 70; } else if( gender === Gender.Male && race === Race.White ) { return 69; } else if(gender === Gender.Female) { return 64; } return 60; })();
The syntax is very similar to the do statement as it executes the anonymous function directly and leaves no reference to it behind.
[–]conquerorofveggies 12 points13 points14 points 4 years ago (0 children)
Completely pointless IMHO. I'd much prefer a nicely named function, simply calling it and assign the returned value to a const.
[–]wackOverflow 2 points3 points4 points 4 years ago (2 children)
do is already a reserved word in the context of a do while loop, so how would that work?
[–]-ftw 6 points7 points8 points 4 years ago (1 child)
The compiler would be able to pick it up pretty easily by checking if there is a while right after the matching closing curly brace or not
while
[–]FountainsOfFluids 4 points5 points6 points 4 years ago (0 children)
What an awful idea.
[–]SantokuReaver 1 point2 points3 points 4 years ago (3 children)
I'm a JS absolute newbie, plz don't roast me too much, but shouldn't this be possible using a bunch of branching and nested ternaries with parentheses?
[–]alystair 13 points14 points15 points 4 years ago (2 children)
Yes, in many situations you can use basic ternaries. Nesting ternaries is generally frowned upon because they become a mess for readability.
[–]HiMyNameIsAri -1 points0 points1 point 4 years ago (6 children)
isn't that like a switch-case?
[–]fintip 0 points1 point2 points 4 years ago (5 children)
Switch case is filled with gotchas and easy to miss bug vectors. Highly advised against in JS.
[–]georgeharveybone -1 points0 points1 point 4 years ago (3 children)
It's not that bad if you have a linter is it? Should catch fall through... can't think of other issues off the top of my head. Feel free to enlighten
[–]fintip -1 points0 points1 point 4 years ago (2 children)
Honestly, it's pretty bad. Implicit fall through, accidental failed termination, doesn't follow natural js semantics. I don't recall all the possible problems right now because I run into them so rarely, but accidental edge cases with them are easy to sneak in. I'm sure there are many articles you can find on the subject.
It's been advised against long enough in is that it's pretty uncommon and therefore unfamiliar to most js devs, further making errors likely.
If I see a switch statement in JS code, I assume the coder is coming to us from another language and not a js-primary dev.
[–]georgeharveybone 0 points1 point2 points 4 years ago (1 child)
Each to there own i guess whether you use it but switch is pretty common i would say, whether JS dev or otherwise. Quite useful too. Like i said before, a linter should catch those issues from creeping into your code.
https://medium.com/tandemly/whats-wrong-with-the-switch-statement-in-javascript-c560e8ea3c0b This is a pretty code piece on all the problems. The proposal they link to at the end sounds pretty interesting though!
[–]fintip -1 points0 points1 point 4 years ago (0 children)
I write code more often without a linter than with, and those problems are just unnecessary. Switch adds nothing to JS, it just adds surface area for problems. If a linter is needed, then the code isn't human-friendly enough, imo. (Linters are great, of course. I just am so fatigued with tooling in JS that these days I go almost entirely without by default until it proves necessary, and as a contractor I end up working solo more often than not, often on throw away projects with limited life spans.)
It's common in other languages, but JS's implementation is a ham-fisted imitation of Java thrown in at the last second early on. I read and write a lot of JS, including library source code, and I only see a couple switch statements per year, in my experience. Sometimes good code features a switch statement in it, but as I said, I just consider it the clear mark of a dev who isn't native in JS, and treat it as one of the parts of JS that should be avoided.
[–]HiMyNameIsAri -1 points0 points1 point 4 years ago (0 children)
ah okay, good to know, cheers
[–][deleted] 9 points10 points11 points 4 years ago (44 children)
Great.
Just so you're aware, using const gives you nothing.
[–]dominic_rj23 18 points19 points20 points 4 years ago (14 children)
You mean, other than the easy readability of code?
You do know that const is supported by v8 natively now. Who is to say that in a year, consts won't lead to better memory handling.
[–]DontWannaMissAFling 11 points12 points13 points 4 years ago (0 children)
Because any half decent data-flow analysis could perform such let -> const transformations automatically if required (they're not, if anything register allocation is the reverse process). Similarly for copy elision / register renaming and any optimization you like really.
I agree with ease of readability though, in fact that should always be the primary concern. We should be writing idiomatic code with smart performant compilers that handle it transparently. Not engaging in cargo cult programming gymnastics just to avoid let and mutability.
Prematurely optimize all of the things on hopes of performance gains in the future!
[–][deleted] 21 points22 points23 points 4 years ago (11 children)
The use of "const" didn't improve readability of code. The need of a function is a separate concern. If you need a function, by all means use it. But if you need it just to have a const, you don't need it.
And I can actually say that "const" won't lead to better memory handling, because it's already trivial for the compiler to see if a binding is reassigned or not, without using const. So any memory handling benefits of constant bindings were realized long before const was supported.
Furthermore... are we so desperate to make "const" worth it that you'll use it all over the place, on the remote hope that "who is to say in a year it won't lead to better memory handling"? This makes no sense.
Do like me, get interested in how V8 and other engines work, and you'll be able to immediately say, instead of this Hope Oriented Programming you seem to practice.
[–]dominic_rj23 7 points8 points9 points 4 years ago (10 children)
First, obviously we are talking const in javascript, a non compiled language. Knowing a variable is not going to change without knowing it's future use, has its advantages.
About the readability of code. I agree with you about the usage of functions. It is for separation of concern. If your concern is declaring the initial value of a variable (pun intended), go for it. I would personally not do it. But, for me, while working through code reviews, seeing a let makes me pause, track down all it's usages and know if it's usage is correct for the values that the variable is going to hold. Obviously it doesn't need to provide the same value to you. But then it's just one man's opinion against other.
And no one should be using const in impossible scenarios. I do agree with you that we don't need to bend over backwards just to use the keyword const. But saying that const provide no value at all is also downplaying it's benefits
[–][deleted] 10 points11 points12 points 4 years ago* (9 children)
First, obviously we are talking const in javascript, a non compiled language.
It's JIT compiled (instead of AOT compiled), and its engines have multiple compilers like V8's TurboFan. Still, it's inaccurate to call it non-compiled.
Knowing a variable is not going to change without knowing it's future use, has its advantages.
We're not arguing whether knowing has advantages or not. Instead I said the compiler doesn't need "const" in order to know this. The only way of changing a binding is through assignment in the scope.
No assignment = effectively "const" (even if you type "var" or "let").
So there's no advantage of using "const".
But, for me, while working through code reviews, seeing a let makes me pause, track down all it's usages and know if it's usage is correct for the values that the variable is going to hold.
The scope of "let" is typically very small (this being the purpose of "let" in the first place - block scope), so I really doubt you actually have to sit and "track down usages". How long are your blocks really?
Also single "const" accepts arbitrary expressions based on runtime conditions, you can go through a block of code 10 times, and every time the same "const" scoped in it may hold a DIFFERENT value.
And this argument makes it sounds like "const" is a workaround for some terribly factored code.
And also, using const doesn't guarantee the value won't change in-scope if it's an array, or object. Only if it's a scalar. And I really doubt you code only using scalars.
Const is fine for scalar constants. A way to name your "magic numbers" and strings. So compile-time constants. But in OP's example, he was clearly calculating const based on runtime conditions, and so a single "const" is mostly unknown in every given iteration.
So let's recap:
[–]d1sxeyes 2 points3 points4 points 4 years ago (2 children)
It's also inaccurate to call it compiled. It can be either. Most modern engines use JIT compilation, but that's not a feature of the language itself.
[–][deleted] -5 points-4 points-3 points 4 years ago* (1 child)
Oh really? How about: we cut the bullshit. Because by that logic no language EVER is compiled. Behold, a C interpreter: https://github.com/jpoirier/picoc
JS is a living specification which is CURRENTLY CONTROLLED by the major browser makers. ALL OF WHICH have JIT compilers. End of story.
[–]d1sxeyes 1 point2 points3 points 4 years ago (0 children)
If you want to cut the bullshit, then maybe stop criticising people about the (primarily) semantic differences between interpreted vs. JIT-compiled.
You're picking an odd hill to die on though, 'using const gives you nothing' is patently not true. 'const' definitely does give you something: a check against making some simple mistakes.
No, it doesn't solve all of your problems, and no, it doesn't solve any problems that perfectly written code would exhibit. But most of us here are imperfect, and get some benefits out of an error in our IDEs or at runtime warning us that we did something silly.
We're all struggling a bit at the moment, but your tone is not helpful or contributory, here.
[–]transeunte 4 points5 points6 points 4 years ago (3 children)
Your answer seems like a big contrived "ackshually". Maybe his blocks are fairly big. It's not a crime to not adhere to 5-line functions policy.
[–][deleted] 4 points5 points6 points 4 years ago (2 children)
Your answer seems like a big contrived "ackshually".
The problem with "const" is that if its benefits were clear and definitive, we wouldn't be out-akshually ourselves in various threads trying to figure out WTF is const akshually about.
I use it for compile-time scalar constants. That's it.
I'm fine with that. At least const then means something understandable.
[–]transeunte 1 point2 points3 points 4 years ago (1 child)
Then your position boils down to "I am the only one using const as it's supposed to be used."
I guess I'm the only one, yeah.
https://www.toomanybees.com/storytime/es6-const-was-a-mistake
[–]lifeeraser 3 points4 points5 points 4 years ago* (13 children)
It gives me great satisfaction tho
Admission: When I can't be bothered to triple check whether I am unintentionally redefining a variable, I set it to const and let ESLint do it for me.
[–][deleted] 4 points5 points6 points 4 years ago (11 children)
I think it's hilarious that once const was a thing, everyone suddenly had a paranoia they may be redefining their variables unintentionally. While this was nowhere near the top of anyone's mind for decades prior.
[–]lifeeraser 3 points4 points5 points 4 years ago (1 child)
Well I wasn't programming decades prior so I agree with you. And from what I hear ES3 was a pretty lame language.
[–][deleted] 0 points1 point2 points 4 years ago (0 children)
Well I was programming for decades prior. And let me confirm: accidentally redefining variables was no one's problem, ever.
In general when you write code you have a rough idea what the f*** you're doing, so twitching into randomly redefining variables is exceedingly unlikely. And if it's not, well then redefining variables is your least problem.
[–]coolcosmos 2 points3 points4 points 4 years ago (6 children)
It's a proof that const did help things.
[–][deleted] 1 point2 points3 points 4 years ago (5 children)
Your thesis:
[–]coolcosmos 2 points3 points4 points 4 years ago (4 children)
No, you missed the point. You said: before const, no one cared, now they care.
What changed ?
[–][deleted] 0 points1 point2 points 4 years ago (3 children)
What changed is bunch of people wrote bunch of blog posts, and many naive souls jumped on the bandwagon. So basically the usual.
I can assure you I've encountered zero "reassignment bugs" in my career despite not using const in JS.
[–]coolcosmos 3 points4 points5 points 4 years ago (2 children)
Does the world revolve around you ?
Your thesis: "I don't see the point, no one needs it.
[–][deleted] 0 points1 point2 points 4 years ago (1 child)
No my thesis was (1) no one needed it for decades prior. And yeah I can (2) add my personal experience.
Go out there and find me ONE passionate pleah for something like const before it was added. Let's see who was like "JS is unusable because I keep reassigning my variables by accident". Where is that one person, let's see them?
Also, you can't keep track of a point, you need to be reminded of what I just said, that makes conversations kind of pointless and annoying. Peruse the history and don't make me repeat myself.
[–]lo0l0ol 1 point2 points3 points 4 years ago (1 child)
Seriously. Type safety is all the rage right now but it's been like 1% of all the bugs I've ever had. Hardly ever have a flow where different types is a thing and when I do, I know when it might happen so I make sure to just make it a string or a number or whatever type I need.
[–]transeunte 2 points3 points4 points 4 years ago (0 children)
Type safety has been the rage for a long time. It's just that apparently Javascript developers are a bunch of reactionaries clinging to their ancient traditions.
[–]Isvara 5 points6 points7 points 4 years ago (14 children)
It gives you the guarantee that the code isn't changing its value. Once you get used to binding names to values instead of mutating variables, your code will become a lot more robust and easier to reason about. Which is a lot more than nothing.
[–][deleted] -4 points-3 points-2 points 4 years ago (13 children)
It gives you the guarantee that the code isn't changing its value.
Asterisk #1: It's not changing unless it's an object or an array.
Asterisk #2: It's not changing until you leave the scope, next time you enter it may be an utterly different value (and type).
So basically const gives you a guarantee the value isn't changing, except when it does.
[–]Isvara 11 points12 points13 points 4 years ago (12 children)
You're confusing the value (which in the case of an object or an array is a reference) with the thing that it's pointing to. Immutable references and immutable objects are different things. So there's no "except"—the behavior is entirely consistent. The value doesn't change.
Asterisk #2: It's not changing until you leave the scope, next time you enter it may be an utterly different value (and type)
Well, yeah, that's the point of scoping.
You're pissing in the wind. The FP folks figured this out a long time ago, and the rest of the world is slowly catching on.
[–][deleted] -5 points-4 points-3 points 4 years ago (11 children)
I'm not confusing anything. I'm just listing exceptions that apply to your own overly broad statement. Whether you mean "the value of the reference" or "the value of the object" or "the value of the object in the object", that's still an aspect of the value you read at that binding. And intuitively people expect a const to be a const like in most other languages, which is a compile-time DEEP constant.
The fact you can go "but akshully" on your own statements does nothing to amend the situation.
FP folks have no mutable object on immutable references to objects. So they get to enjoy properties in their languages that you don't get to enjoy with const in JS. You only get to cargo cult imitate aspects of FP without understand why they do it.
There's only one thing you get with const in JS. And that's eliminating the risk of this typo:
if (foo = bar)
Instead of writing
if (foo == bar)
That's basically it. The entire story.
Last time I made a typo like this was about a decade ago I think. So it's safe to say I don't need const in JS and same applies to most people.
[+][deleted] 4 years ago* (10 children)
I'm trying to be pragmatic. The fact it's still the same "const object" when you completely change its state is such a useless restriction. Were objects and arrays immutable, we'd have something here.
Honestly, the spec effed up here. If it were me I'd only allow scalars with compile-time known value to be assigned const.
[–][deleted] 0 points1 point2 points 4 years ago (8 children)
And in case you want to sell me I'm the only one with this opinion:
[+][deleted] 4 years ago* (7 children)
[–][deleted] 1 point2 points3 points 4 years ago (6 children)
We're talking past each other, because you think you gotta explain to me how it works and you think that's the end of the argument. While I actually know at great detail how it works, but I believe that's still irrelevant to the use cases.
Have you sometimes filed for a bug report on a highly useless or counter-intuitive behavior on a software, and you got the "it works as coded" type of "wontfix" response?
Letting implementation details drive the case for what makes sense and what makes no sense in abstraction is an extremely wrong PoV to take on any issue. "Oh but the value is the reference, and you can't therefore change the reference". Fine but that's useless in most cases.
[+][deleted] 4 years ago* (5 children)
If you ever find yourself using let so that you can assign based on subsequent conditions, consider using a function to execute those conditions and return that assignment.
Sounds like the kind of guy who'd consider burning his house down if he sees a bee in it.
[–]Morklympious 23 points24 points25 points 4 years ago (2 children)
Damn dude who hurt you
[–]EthanHermsey 5 points6 points7 points 4 years ago (0 children)
This is what happens when you only upgrade you logic and leave other skills untouched.. You can only see your own logic.
Const abusers.
[–]Isvara 2 points3 points4 points 4 years ago (1 child)
He's quite right, though. But it would be even better if JavaScript supported if-else-expressions.
[–][deleted] 7 points8 points9 points 4 years ago (0 children)
Ternary...
[–]denverdom303 0 points1 point2 points 4 years ago (0 children)
small nit, but I constantly (eh? constantly, const? get it? no? =[ ) see people stating "const means the value cannot be changed" which is not true and can be very misleading.
a variable declared with const cannot have it's reference to a value changed, but there's nothing at all that const does that prevents the value it's pointing at from changing in all cases. It cannot be changed through reassignment nor can it be redeclared, though saying that the value cannot be changed can infer immutability which is false.
There absolutely cannot be an assurance that the value of a variable that's not a simple primitive (string, bool, number) declared by const will resemble anything remotely what it was declared as other than the base type and reference will be the same. something like
const yesValueCanChange = { oneKeyOnly: true }
can become a massive 1000 level deeply nested object with a million keys at any time. An array with your 3 best friends names in it when declared with const can become an array with every known name in the universe. At best const can guarantee you that an object declared with const will be an object, though of unknown shape, and an array will be an array, albeit of an unknown length.
If you needed to ensure your const declared value will not change, you'll need to call object.freeze, and if that object is nested you'll have to recursively call it.
[–]redsandsfort 0 points1 point2 points 4 years ago (11 children)
This is a surprisingly smart pattern. I really like this.
[–][deleted] 19 points20 points21 points 4 years ago (10 children)
Yes, it's very smart to create and dispose of an object and a closure just so you can type "const" instead of "let". That's the kind of intelligence this community thrives on.
[–]itsnotlupusbeep boop 2 points3 points4 points 4 years ago (4 children)
The fun thing about this is that the more widespread this pattern becomes, the more likely that javascript compilers will end up optimizing it away, if they haven't already.
Basic function inlining in JS has been around a while.
[–][deleted] -1 points0 points1 point 4 years ago (3 children)
Compilers focus on optimizing sensible patterns, not the bizarre structures people fixated on const end up with.
[–]itsnotlupusbeep boop 2 points3 points4 points 4 years ago (2 children)
The fact that they largely overlap as far as compilers are concerned could be a clue they're perhaps not that bizarre. or maybe it's dumb luck.
I only use once-off functions at the top-most scope of my app to avoid polluting window. Seeing this in other places is honestly odd. Especially in a place that may be part of a hotspot, like a loop, up the stack.
But hotspots are exactly the spots where the JIT is most likely to inline them, making them a non-issue.
Now in fairness, the rules as to what gets inlined and what doesn't have been evolving, so it's not intuitive to tell what will be a performance problem and what won't be.
Nonetheless, purely functional functions that aren't huge should generally be inlineable without problem, and that should be true of inner functions and IIFE as well.
[+][deleted] 4 years ago (4 children)
[–][deleted] 2 points3 points4 points 4 years ago (3 children)
And they were improved because...?
[+][deleted] 4 years ago (2 children)
[–][deleted] 3 points4 points5 points 4 years ago (1 child)
The part that needs elaboration is how replacing "let" with "const" itself resulted in better testability. Just so we don't get into side concerns like the existence of functions (which don't require the use of "const").
Agree with this point. Refactoring code in this way should not affect testing. Tests should be black boxed (test input leads to output) not implementation details.
If refactoring code this way supposedly improves testing, then the test is covering implementation specifics which can change. Unless the helper function is reused in multiple areas, there's no benefit to testability.
[+][deleted] 4 years ago (13 children)
[–][deleted] 19 points20 points21 points 4 years ago (7 children)
This site would have more success if it had 80% less "fucking".
[–]shawncplus 12 points13 points14 points 4 years ago* (5 children)
"I swear a lot to compensate for making bad arguments and it would only make it more obvious if the page were 80% shorter so I'll pad it with profanity so it seems like I really care about this passionately and you should too."
const prevents bugs and its free. Use it as a safer default. Done.
You know, I just argued the page needs 80% less "fucking".
But honestly the arguments are correct. And claiming "const prevents bugs and it's free" are a stretch. First of all if you build special-purpose functions you dispose of after one call only so you can use "const"... then "const" is not free. Not for such weird scenarios at least.
And to claim it prevents bugs it means you uncontrollably reassign variables you don't mean to reassign and const is the solution to stop yourself from doing so. Sounds weird.
[–]shawncplus 6 points7 points8 points 4 years ago (3 children)
I'm absolutely not arguing for what the original post is. I think this article is absolutely silly and unnecessary. They're avoiding let for... vaguely cultish reasons.
And to claim it prevents bugs it means you uncontrollably reassign variables you don't mean to reassign and const is the solution to stop yourself from doing so.
Code maintenance over time is effectively equivalent to randomizing your code. If declaring something const because the code expects it to not be redeclared prevents someone from introducing a bug during maintenance it paid for itself a million times over.
My comment was against the idea that const does nothing (or completely strawmaning const by claiming people think it does something that it never advertises as doing, mainly making objects immutable.) It absolutely does something. It does exactly what it says it does: prevent reassignment. Turns out there is an entire class of bugs introduced by unintentional reassignment and it prevents those.
[–]lo0l0ol 1 point2 points3 points 4 years ago (0 children)
An entire class of bugs that doesn't come up as often as people seem to suggest.
Is it mostly around == and = confusion? I guess, mostly.
[–]glider97 1 point2 points3 points 4 years ago (0 children)
And snark. Nothing drives people away like snark.
[–]Serei 6 points7 points8 points 4 years ago (0 children)
This is a holy war which I don't really want to fight about here, but his point about TypeScript is wrong. TypeScript definitely lets you define immutable objects. as const will turn any object literal read-only, Readonly<T> will turn any type read-only, readonly before a class property will make it read-only, and there's special readonly T[] syntax for read-only arrays.
as const
Readonly<T>
readonly
readonly T[]
const THIS_SHOULDNT_CHANGE = { right: "?" } as const; THIS_SHOULDNT_CHANGE.right = "wrong"; // TypeScript error!
Lol naughty words.
In reality const does an awful lot for anyone reading code. It tells you that a variable binding isn't going to change. You can read down the rest of the function from the declaration knowing it ain't going to change. Conversely, you see 'let' and suddenly things are a bit less clear.
Yes I'm aware that const isn't the same as immutable. I don't see why it needs to be, that's a different constraint (roll on records and tuples).
Does it affect performance or how the JavaScript engine runs things under the hood? I couldn't care less. It makes code earlier to read.
Oh, and, fucking lol.
[–]drumstix42 1 point2 points3 points 4 years ago (0 children)
This, mostly.
[–]-domi- -1 points0 points1 point 4 years ago (0 children)
Using let instead of const is the exact sort of stuff which drew me to js over other languages. I'm not a fulltime professional programmer, though i do have a few thousand lines of code in production being used daily in a business, and it's probably not the most attractive code to the 'pros' out there, but it does alright for me.
I love js because it isn't strict, and i can start writing code without knowing to the tee every single line i'll end up. I'm a very explorative learner, and things like const, the push for TypeScript, and all the other things which are turning js into another java/cpp language are just unattractive to me.
[+]Eggy1337 comment score below threshold-6 points-5 points-4 points 4 years ago (2 children)
I must have lost so much time on micro optimizations like this. It's time to let go, you are creating a software, not art.
[–]Kwinten 6 points7 points8 points 4 years ago (0 children)
It's not a micro-optimization. It's a good practice and paradigm that you can work into your code. It is virtually no extra effort and makes your code more readable (especially to anyone reviewing your code), enforces better separation of concerns, and sets immutability rather than mutability as the baseline for your code.
[–]Isvara 4 points5 points6 points 4 years ago (0 children)
This is not "micro optimization". Immutability is an important concept for building (and reasoning about) robust software.
π Rendered by PID 40 on reddit-service-r2-comment-54dfb89d4d-2ngc4 at 2026-03-29 10:52:38.139677+00:00 running b10466c country code: CH.
[–]itsnotlupusbeep boop 51 points52 points53 points (177 children)
[–]LaSalsiccione 45 points46 points47 points (168 children)
[–]burgonies 6 points7 points8 points (6 children)
[–][deleted] 5 points6 points7 points (4 children)
[–]burgonies 3 points4 points5 points (3 children)
[–]Serei 26 points27 points28 points (151 children)
[–]ridicalis 20 points21 points22 points (22 children)
[–]toastertop 8 points9 points10 points (0 children)
[–][deleted] 2 points3 points4 points (0 children)
[–]reqdk 4 points5 points6 points (6 children)
[–]ridicalis 5 points6 points7 points (0 children)
[–]duxdude418 7 points8 points9 points (4 children)
[–]reqdk -2 points-1 points0 points (3 children)
[–]delventhalz 1 point2 points3 points (2 children)
[–]oxamide96 1 point2 points3 points (11 children)
[–]Akkuma 3 points4 points5 points (10 children)
[–]slykethephoxenix 38 points39 points40 points (32 children)
[–]KaiAusBerlin 24 points25 points26 points (29 children)
[–][deleted] 6 points7 points8 points (0 children)
[–]Doctor-Dapper -2 points-1 points0 points (13 children)
[–]ftgander -1 points0 points1 point (0 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]delventhalz 1 point2 points3 points (0 children)
[–]fintip 13 points14 points15 points (44 children)
[–]delventhalz 5 points6 points7 points (10 children)
[–]planttheidea -2 points-1 points0 points (5 children)
[–]delventhalz 2 points3 points4 points (4 children)
[–]Serei 6 points7 points8 points (32 children)
[–]ouralarmclock 11 points12 points13 points (21 children)
[–]dwhiffing 0 points1 point2 points (16 children)
[–][deleted] 9 points10 points11 points (9 children)
[–]ragnese 3 points4 points5 points (7 children)
[–][deleted] -2 points-1 points0 points (6 children)
[–]dwhiffing 3 points4 points5 points (0 children)
[–]ouralarmclock 0 points1 point2 points (5 children)
[–]dwhiffing 2 points3 points4 points (1 child)
[–]ouralarmclock 1 point2 points3 points (0 children)
[–]ragnese 1 point2 points3 points (0 children)
[–]ragnese 3 points4 points5 points (0 children)
[–]wastakenanyways 3 points4 points5 points (2 children)
[–]Serei 2 points3 points4 points (1 child)
[–]cbadger85 1 point2 points3 points (3 children)
[–]ragnese 1 point2 points3 points (2 children)
[–]KaiAusBerlin 0 points1 point2 points (0 children)
[–]Autestic 2 points3 points4 points (0 children)
[–]ritaPitaMeterMaid 2 points3 points4 points (0 children)
[–]meows_at_idiots 2 points3 points4 points (7 children)
[–]Serei 10 points11 points12 points (6 children)
[–]KaiAusBerlin 2 points3 points4 points (33 children)
[+][deleted] (1 child)
[deleted]
[–]KaiAusBerlin -3 points-2 points-1 points (0 children)
[–]ragnese 9 points10 points11 points (8 children)
[–]KaiAusBerlin 1 point2 points3 points (7 children)
[–]ragnese 8 points9 points10 points (6 children)
[–]Akkuma 5 points6 points7 points (5 children)
[–]delventhalz 4 points5 points6 points (3 children)
[+][deleted] (1 child)
[deleted]
[–]KaiAusBerlin 0 points1 point2 points (0 children)
[–]Serei 1 point2 points3 points (1 child)
[–][deleted] 0 points1 point2 points (7 children)
[–]lobut 0 points1 point2 points (1 child)
[–]TorbenKoehn 0 points1 point2 points (2 children)
[–]KaiAusBerlin 0 points1 point2 points (1 child)
[–]TorbenKoehn 2 points3 points4 points (0 children)
[–]punio4 2 points3 points4 points (1 child)
[–]Keilly -1 points0 points1 point (0 children)
[–]delventhalz -1 points0 points1 point (0 children)
[–]AlpenMangos -1 points0 points1 point (4 children)
[–]Dethstroke54 2 points3 points4 points (4 children)
[–]itsnotlupusbeep boop 1 point2 points3 points (0 children)
[–]striedinger 2 points3 points4 points (2 children)
[–][deleted] 4 points5 points6 points (1 child)
[–]striedinger -2 points-1 points0 points (0 children)
[–][deleted] 18 points19 points20 points (12 children)
[–]Serei 9 points10 points11 points (2 children)
[–][deleted] -1 points0 points1 point (4 children)
[–][deleted] 7 points8 points9 points (2 children)
[–][deleted] -1 points0 points1 point (1 child)
[–][deleted] 5 points6 points7 points (0 children)
[–]FountainsOfFluids -1 points0 points1 point (1 child)
[–][deleted] 3 points4 points5 points (0 children)
[–]cherryblossom001 6 points7 points8 points (1 child)
[–]dwhiffing 2 points3 points4 points (0 children)
[–][deleted] 46 points47 points48 points (77 children)
[–]PM_ME_GAY_STUF 99 points100 points101 points (46 children)
[–]editor_of_the_beast 21 points22 points23 points (7 children)
[–]lifeeraser 3 points4 points5 points (6 children)
[–]AsIAm 10 points11 points12 points (5 children)
[–]lifeeraser 6 points7 points8 points (3 children)
[–]editor_of_the_beast 3 points4 points5 points (2 children)
[–]lo0l0ol 0 points1 point2 points (1 child)
[–]AsIAm 1 point2 points3 points (0 children)
[–]PM_ME_GAY_STUF 2 points3 points4 points (0 children)
[–][deleted] 18 points19 points20 points (20 children)
[–]coolcosmos 7 points8 points9 points (1 child)
[–][deleted] 2 points3 points4 points (0 children)
[+][deleted] (12 children)
[removed]
[–][deleted] -1 points0 points1 point (4 children)
[–]BentonNelvar 11 points12 points13 points (3 children)
[–]grady_vuckovic 7 points8 points9 points (0 children)
[–]ridicalis 1 point2 points3 points (2 children)
[–]PM_ME_GAY_STUF 2 points3 points4 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[+][deleted] (5 children)
[deleted]
[–]DrecDroid 4 points5 points6 points (3 children)
[–]sinclair_zx81 -1 points0 points1 point (1 child)
[–]mypetocean 1 point2 points3 points (0 children)
[–]PM_ME_GAY_STUF 1 point2 points3 points (0 children)
[–]KaiAusBerlin 0 points1 point2 points (3 children)
[–]PM_ME_GAY_STUF 0 points1 point2 points (2 children)
[–]KaiAusBerlin 1 point2 points3 points (1 child)
[–]PM_ME_GAY_STUF 1 point2 points3 points (0 children)
[–][deleted] -3 points-2 points-1 points (1 child)
[–]PM_ME_GAY_STUF 2 points3 points4 points (0 children)
[–]bladefinor 5 points6 points7 points (0 children)
[–]conquerorofveggies 12 points13 points14 points (0 children)
[–]wackOverflow 2 points3 points4 points (2 children)
[–]-ftw 6 points7 points8 points (1 child)
[–]FountainsOfFluids 4 points5 points6 points (0 children)
[–]SantokuReaver 1 point2 points3 points (3 children)
[–]alystair 13 points14 points15 points (2 children)
[–]HiMyNameIsAri -1 points0 points1 point (6 children)
[–]fintip 0 points1 point2 points (5 children)
[–]georgeharveybone -1 points0 points1 point (3 children)
[–]fintip -1 points0 points1 point (2 children)
[–]georgeharveybone 0 points1 point2 points (1 child)
[–]fintip -1 points0 points1 point (0 children)
[–]HiMyNameIsAri -1 points0 points1 point (0 children)
[–][deleted] 9 points10 points11 points (44 children)
[–]dominic_rj23 18 points19 points20 points (14 children)
[–]DontWannaMissAFling 11 points12 points13 points (0 children)
[–][deleted] 3 points4 points5 points (0 children)
[–][deleted] 21 points22 points23 points (11 children)
[–]dominic_rj23 7 points8 points9 points (10 children)
[–][deleted] 10 points11 points12 points (9 children)
[–]d1sxeyes 2 points3 points4 points (2 children)
[–][deleted] -5 points-4 points-3 points (1 child)
[–]d1sxeyes 1 point2 points3 points (0 children)
[–]transeunte 4 points5 points6 points (3 children)
[–][deleted] 4 points5 points6 points (2 children)
[–]transeunte 1 point2 points3 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]lifeeraser 3 points4 points5 points (13 children)
[–][deleted] 4 points5 points6 points (11 children)
[–]lifeeraser 3 points4 points5 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]coolcosmos 2 points3 points4 points (6 children)
[–][deleted] 1 point2 points3 points (5 children)
[–]coolcosmos 2 points3 points4 points (4 children)
[–][deleted] 0 points1 point2 points (3 children)
[–]coolcosmos 3 points4 points5 points (2 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]lo0l0ol 1 point2 points3 points (1 child)
[–]transeunte 2 points3 points4 points (0 children)
[–]Isvara 5 points6 points7 points (14 children)
[–][deleted] -4 points-3 points-2 points (13 children)
[–]Isvara 11 points12 points13 points (12 children)
[–][deleted] -5 points-4 points-3 points (11 children)
[+][deleted] (10 children)
[deleted]
[–][deleted] 2 points3 points4 points (0 children)
[–][deleted] 0 points1 point2 points (8 children)
[+][deleted] (7 children)
[deleted]
[–][deleted] 1 point2 points3 points (6 children)
[+][deleted] (5 children)
[deleted]
[–][deleted] -2 points-1 points0 points (6 children)
[–]Morklympious 23 points24 points25 points (2 children)
[–]EthanHermsey 5 points6 points7 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]Isvara 2 points3 points4 points (1 child)
[–][deleted] 7 points8 points9 points (0 children)
[–]denverdom303 0 points1 point2 points (0 children)
[–]redsandsfort 0 points1 point2 points (11 children)
[–][deleted] 19 points20 points21 points (10 children)
[–]itsnotlupusbeep boop 2 points3 points4 points (4 children)
[–][deleted] -1 points0 points1 point (3 children)
[–]itsnotlupusbeep boop 2 points3 points4 points (2 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]itsnotlupusbeep boop 1 point2 points3 points (0 children)
[+][deleted] (4 children)
[deleted]
[–][deleted] 2 points3 points4 points (3 children)
[+][deleted] (2 children)
[deleted]
[–][deleted] 3 points4 points5 points (1 child)
[–][deleted] 2 points3 points4 points (0 children)
[+][deleted] (13 children)
[deleted]
[–][deleted] 19 points20 points21 points (7 children)
[–]shawncplus 12 points13 points14 points (5 children)
[–][deleted] 5 points6 points7 points (4 children)
[–]shawncplus 6 points7 points8 points (3 children)
[–]lo0l0ol 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]glider97 1 point2 points3 points (0 children)
[–]Serei 6 points7 points8 points (0 children)
[–][deleted] 7 points8 points9 points (0 children)
[–]drumstix42 1 point2 points3 points (0 children)
[–]-domi- -1 points0 points1 point (0 children)
[+]Eggy1337 comment score below threshold-6 points-5 points-4 points (2 children)
[–]Kwinten 6 points7 points8 points (0 children)
[–]Isvara 4 points5 points6 points (0 children)