This "assignment is caching is bad" analogy does not hold any water.
You get a result from a call to `foo(bar)`. You have to _do something_ with that result. One common thing you'd need to do is to call another function: _baz(foo(bar))_. But then you're just hiding the assignment inside a baz function call (the result of _foo(bar)_ will be available as a variable/constant inside of _baz_).
That doesn't so bad if you only need to do one thing with with the result of `foo(bar)`. Now what if you have to do something with that result twice. In this case all you've done is reduce the scope of a constant to be smaller than it needs to be, requiring you to make a duplicate `foo(bar)` call.
Now you're repeating yourself and you don't know anymore if you're conceptually dealing with the same result or if foo(bar) might produce a different result on second call. You removed philosophical/semantic meaning from your code and did not gain anything from it.
If you find yourself wanting/needing to "expire" variables that you define before you run out of scope, then the answer is a combination of:
1) use constants of immutable data structures, not variables or mutable structures
2) better name such constants so that you know what they represent
3) better manage scope and function size
In practice, the above is much easier to achieve than what you're proposing, and makes the code easier to read and maintain.
> The right way instead is to evaluate (or "re-evaluate") the function every time you need it unless you have a good reason not to (the only good reason is that the function is a bottleneck that affects the experience of the user)
That does not scale to using the coding paradigm that you're proposing application-wide. Your whole app will be one big bottleneck because it's doing a multiple of the computations that it needs to be doing, with no easy way out. I guess you can get away with that by throwing more money at your backend infra, but you can't do that on mobile or for web frontends or desktop apps.