I would disagree that it's super-easy to reason about var, despite being lexically scoped. It still causes an enormous amount of confusion when loops and callbacks are used together.
The PI example only really works because we all know what PI should look like. If you were using someone else's constant value and it accidentally got rebound it would be much harder to know.
Also, here’s my question: If I can write:
const PI = 3.14159265;
Why can’t I write: const function diameter (r) { return 2 * PI * r; }
??? var function diameter() {}
It's definitely a shame that the only way to achieve consistent behaviour between variables and named functions requires you to write the name twice. const diameter = function diameter() {};
If it wasn't for the usefulness of named functions for debugging and hoisting, I would just use: const diameter = function() {};Most people don't like hoisting -- and I agree that variable hoisting is crazy. I'd never advocate this:
a = 2;
var a;
But function hoisting I find super useful. I always prefer to write my files like this: foo();
bar();
// ....
function foo() { .. }
function bar() { .. }
...because when I open a file, I don't want to go hunting for any executable code, I just want to look at the very top. Function declaration hoisting lets me put those definitions at the bottom and the code that uses them at the top.I've found this to be much more useful in code maintenance.
const diameter = () => {};
export const radius = () => {};
Could be wrong.Otherwise, the arrow itself is anonymous and thus you don't have a name to make an inner self-reference with.
This is possible, but has no utility beyond the original.
const diameter = function diameter (r) { return 2 * PI * r; }A function expression bound to a constant block-scoped variable does not have the exact same semantics.
I don't think the former is all that useful, and the latter is super useful but `const` doesn't do anything to help with that.
If I see PI = 3.14159265 somewhere in a file, it’s not a hardship to assume it will not be rebound, and to notice if it is rebound.
The super-important thing to reason about is value mutability, because that escapes lexical scope. We pass mutable values to library functions containing code we have never read. We integrate with code written by a colleague who is in another time zone and may accidentally change a routine to mutate an array we pass with .push instead of .concat.
“Easier to reason about” is massively important with mutability. Not so much with lexical bindings.