When I have to go back to programming in a language without const declarations it feels bad.
It took about two weeks to train my hands/brain to type const before let/var.
I think running eslint --fix will even change your "let"s to "const"s where appropriate, but don't quote me on that.
Yep, this is the relevant rule - http://eslint.org/docs/rules/no-var
Though it just replaces all var with let. I expected it to intelligently use either const or let depending on how the variable is used ¯\_(ツ)_/¯
It does exactly what you describe :)
While I agree that const/let is a useful convention for communicating mutability, it isn't nearly a big enough deal to warrant the attention it receives from the community.
It's not just const/let; I rarely make a front end PR that isn't bike-shedded to death over subjective styling choices, single quotes vs double quotes, etc. It often feels like conforming to flavor-of-the-week, subjective decrees from frontend trendsetters is more important than the substantive work that your code is doing.
I agree that pull requests that mass change from let to const are largely a waste of time, but usage of const vs let is a legitimate discussion within your team.
- Tabs vs spaces.
- Vi vs Emacs
- Weak vs strong typing
- where to place {} in block statements
- where to put commas
No, programming in general is susceptible to these trivial holy wars.
Not trying to derail the convo or take sides, but one of these is not like the others ;)
The ONLY holy war in JS is the semi-colon one
:^)
The point still stands
but yeah.
const foo = {bar: 1}
foo.bar = 2;
It will only avoid having the pointer re-pointed to another object. It's better to just try avoiding global variables, and use a naming convention like uppercase and/or underscore for constants and global variables.Const is probably only meant for constants like the name suggests.
I think something like this is pretty safe from reassigning:
{
let foo = 1
...
}
...
If you want more control over your properties, you can use the ES5 feature "defineproperty" where you can set writeable: false const foo = {bar: 1}
The only thing const about it is the reference `foo` cannot be reassigned: foo = something_else; // error
Unlike `const` in C++, `const` in javascript in not very useful in my opinion. `let` is shorter and more readable.> it can help you write stateless code if you assume immutability
Sorta. I mean you're right but at the same time if you're using const for an object or array then it doesn't really matter without `object.freeze()` because it's not immutable only the reference is and I don't think most JavaScript developers understand that (at least not most of the ones I've run into).
What constitutes holy wars are often the most accessible[1]
const array = [1, 2, 3];
array.push(100); // unexpected?
I prefer to use let for bindings to objects that get mutated, even if the variable is not re-bound.For anyone not in the know, declaring `const` on an object only makes it where you can't re-assign the object, but you can still mutate its 'members'.
Personally, I use `let` just to symbolize that it isn't a constant and does change even though I could declare it a `const`.
I think it makes the code more readable.
The problem is that, while a lot of things can be expressed elegantly this way, sometimes the most maintainable thing, or the most efficient thing, is to have some side effects in a deep loop in a certain algorithm, and it's very difficult to do this with purely functional JS.
The real solution is to allow your const bindings to be mutated when you need to, and comment explicitly to make things perfectly clear!
e.g.
const x = {};
x.foo = 'it works!' type const * const
Which is a const pointer to a const type, making both the pointer and the data immutable. immut x = {};
x.foo = 'it doesn't work! :)'
At the moment, we can use these libs to achieve itJust use `const` + `Object.freeze()`; it'll get you 99.9995% of exactly what you want.
Fair enough though I'm not convinced you should be hitting this type of use case in your code (kinda inefficient and sounds awkward to make a small change to a large object and yet need both objects to continue to be in memory, separated). At least not typically / frequently.
> if you're trying to keep your data truly immutable, that copy operation is going to be a pain to write with the built-in tools, whereas it's super easy to return a copy of an object with a change to a single, deeply nested property with Immutable.js.
While it is a little bit of a pain almost every framework and probably half of the libraries in existence on npm have a copy function. I'd like to think it's a rare use case but when it's needed you likely don't have to install a new library to handle a copy operation.
> I agree that it's premature to reach for a library before you need it, but let's not pretend there aren't rather large drawbacks to using Object.freeze and Object.assign.
I'm not sure anyone was pretending anything of the sort here and I don't understand the assumption of such. There are plenty of drawbacks but I'm also not convinced it doesn't fit the 95% use case.
> While it is a little bit of a pain almost every framework and probably half of the libraries in existence on npm have a copy function.
The problem isn't just the usability of the copy operation (and even if it were, you still have the performance issue); there is also the problem of JavaScript not enforcing immutability of nested objects with Object.freeze. So if you want to enforce that, you're going to have to call Object.freeze on every child object, which becomes a nightmare to write and maintain.
Sure. That's why I made sure to say it'll give you 99% of what you want. Not 99% of immutable data structure capabilities :).
Though I'm sure folks may disagree with what I'm suggesting they "want" but I do not believe it's a good pattern to follow where a complex object needs to be immutable in JavaScript.
> JavaScript not enforcing immutability of nested objects with Object.freeze. So if you want to enforce that, you're going to have to call Object.freeze on every child object, which becomes a nightmare to write and maintain.
Which is why you should never ever do that. It's a bad pattern in a dynamic language to try and make complex structures completely immutable. It's best to simply find alternative ways of accessing them if you do not want to expose it to modification.
const x = Object.freeze({
y: {
foo: 'bar'
}
});
x.y.foo = 'baz'
console.log(x.y.foo) //baz
immutablejs might be overkill, but not having, and using, a recursive freeze is going to bite a lot of people if the advice is just 'const + Object.freeze'.No one should be trying to use a recursive freeze (if they are I would argue their data structure is poorly suited to be immutable).
I'm not saying `const` + `Object.freeze()` gets you Immutablejs I'm saying it gets you, likely, what you want / need.
const x = Object.freeze([
{id: 1, value: 'foo'},
{id: 2, value: 'bar'},
{id: 3, value: 'baz'},
])
...
//Bug in the code
x[0].value = 'test'
First comment on the bug report was:'This shouldn't be possible as the array is const and frozen'.
their data structure is poorly suited to be immutable
An array of object seems completely reasonable. Even an array of objects, where those objects themselves have keys which are objects/arrays doesn't seem unreasonable.
We'll just have to agree to disagree.
Yeah const and Object.freeze() are not exactly the most intuitive depending on your level of JavaScript internals knowledge (and even then I don't think const is very intuitive but I digress).
> We'll just have to agree to disagree.
Fair enough! I would just caution trying to make complex objects immutable; it can be handy if you're developing a library and don't trust the dev on the other side (to a degree, copying may be preferable depending on the context) but it can complicate things and lead to some performance and development pattern issues.
If it affected the value it pointed to, what would happen in this type of situation?
let x = {};
const y = x;
x.a = 5;The answer is it works fine. x.a === y.a === 5
This is because you are simply declaring the binding of y to the object bound to x constant. This does not impact your ability to rebind x or to alter the contents of the object, it simply prevents you from rebinding y.
let x = {a:5}
x = {}
console.log(x.a) // undefined
--- const y = {a:5}
y = {} // Uncaught TypeError: Assignment to a constant variable.
--- let x = {a:2}
const y = x
x.b = 12
x = {}
x.b = 13
console.log(y) // {a: 2, b:12}
console.log(x) // {b: 13}I guess one alternative idea for how const would work could be an implementation where `x.a = 5` worked but `y.a = 5` failed. But then what happens if you pass `y` into a function which then tries to assign the `a` property on it? Is the const-ness part of the value passed into the function, or is it a property on variable bindings, and you could only pass `y` to functions that accepted a const variable? That kind of function type checking isn't something usual to javascript currently. And then is the const-ness deep? Is `y.foo.a = 5;` blocked? Mutable DOM elements are a big part of javascript. If the object happened to contain a reference to an element that needed to be manipulated, then you won't be able to do something like `y.foo.element.textContent = "new foo content";`. Going down this road it's now getting to be a pretty big feature that doesn't cleanly fit with the rest of the language or common tasks.
Maybe the naming is a little unfortunate: Javascript's `const` has more in common with Java's `final` than C's `const`.
Now I am going back to change all the object declarations to const.
Const very rarely saves you from bugs and the bugs that saves you from are very easy to find and fix. On the other hand the time wasted by thinking where whether to write const or let and the time wasted by switching consts for lets (and other way around) outweighs the time saved by potentially preventing these easy to find bugs. To sum it up, if consts does not really provide any extra value, why not make your life easier and just use let everywhere.
It was from very senior c++ programmer, so I am not sure how well that translates to JavaScript.
JavaScript const is just a matter of typing 2 more characters and in exchange you make your code more readable (because you communicate "this stuff will never change from here on", which makes understanding the stuff that does mutate easier). There are no far-reaching consequences. Just type "const" everywhere.
I'm not familiar with C++, can you explain more?
First pointers and references. For simplicitly I'm going to ignore references and focus on pointers - the difference is not very interesting in this context. In most languages you probably know, referring to objects is done implicitly: variables that "are" objects are actually references to objects located elsewhere, and variables that are primitive types (numbers, booleans, strings) are just right there. Because of this, in JavaScript you can do this:
var a = {};
var b = a;
b.moo = 6;
a.moo === 6; // true
In here, a and b point to some object that "is" neither a or b - the object itself just floats around in memory and it'll exist until neither a, b, nor anyone else points to it anymore and the GC decides it has to go.In C++, you'll need pointers or references for this, eg.
somestruct a;
somestruct* b = &a; //b now points to a
a.moo = 6;
b->moo == 6; // true
(-> is just C++ shorthand for "follow the pointer and then do a property lookup).Ok now const.
somestruct const a;
a.moo = 6; // error! can't modify a const.
Ok well how about somestruct a;
somestruct* const b = &a;
b->moo = 6;
a.moo === 6; // true
This means the pointer is const. That works because we never change where b is pointing to. So how about: somestruct a;
somestruct const* const b = &a;
b->moo = 6;
a.moo === 6; // true
Oh damn. Crying baby. Const functions will have to wait for some other day.Rust makes it much harder to make these kinds of erros by making variable ownership, reference lifetime, and const-by-default core to the language design. https://doc.rust-lang.org/book/ownership.html ... You do end up spending a lot of time "fighting the compiler," even compared to template-heavy C++ codebases, but the systems you create are free from an entire class of errors.
clang++: error: cannot assign to variable 'b' with const-qualified type 'const somestruct *const'
g++: error: assignment of member ‘somestruct::moo’ in read-only object
The well-known good practice: use const by default; use let when it's needed. At the release of ES6, it was the way to go. But everyday I notice libraries—and some really famous— that use let everywhere in their docs, or some really influent developers from Google or Facebook who share samples of code on Twitter using let when it's not needed [1]. I don't know why. Seems like most people now think that const is for declaring constants (in the traditional meaning, like const API_URL) when it's just the normal way to declare variables that don't need to be reassigned (so basically most variables).
Dan Abramov said: "some people say const is ugly" [2]. Well, if it's a matter of appearance...
[1] https://twitter.com/addyosmani/status/789126892402204673
[2] https://twitter.com/dan_abramov/status/783708858803978240