3 ms·
JS already has immutable objects with `Object.freeze()`. Personally I just use TypeScript which can enforce not mutating at compile time (for the most part).
by felixfbecker 7y ago
JS already has immutable objects with `Object.freeze()`.
Personally I just use TypeScript which can enforce not mutating at compile time (for the most part).
- afandian 7y agoThanks. But can I then add and remove items from an immutable object to create new objects? Part of the immutable value proposition is being able to work with the objects. Based on [0] Freezing feels more like constant than immutable. And the 'frozenness' isn't communicated through the language - I could be passed a frozen or unfrozen object and I wouldn't know without inspecting it. And freeze isn't recursive against the entire object graph, meaning the nature of freezing is entirely dependent on the implementation of that object. I really like the language-level expression and type checking of Rust. But it does require intentional language design. I'm not criticising JS (though I think there are plenty of far better langauges). Just saying that calling `freeze` 'immutable' isn't the full story. [0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- underwater 7y agoHave you looked at Immer.js? It allows you to express modifications to immutable objects as a series of imperative operations. In my experience most "immutability" in JS is enforced by convention or, at best, static type systems. It's not ideal, but it works.
- dvlsg 7y agoLenses in ramda work well, too, if you don't mind being functional in your js code. I suppose that still only fits in the "immutable by convention" category, though.
- Klathmon 7y agoObject.freeze is kind of constant, but you can still easily copy and work with the objects if you need to, for example, the following is valid for most objects: const foo = Object.freeze({ a: 1, b: 2 }) const fooCopy = { ...foo } And you are right that Object.freeze doesn't work recursively (although making it work recursively is fairly easy to implement yourself if you use it a lot). But like it or not JS isn't a language with a powerful type system, and it doesn't pretend to have one so knocking it for that is like knocking Python for using whitespace, or knocking Rust for needing a compiler. Luckily, Typescript and Flow have most of what you are asking for, and they work pretty damn well across the entire ecosystem. Off the top of my head, I know typescript has the ability to mark things as read-only even at the individual property level. [1] And they have tons of the type checking nice-ness that you can expect from other "well typed" languages like Rust. [1] https://basarat.gitbooks.io/typescript/docs/types/readonly.html https://basarat.gitbooks.io/typescript/docs/types/readonly.h...
- mrighele 7y ago> But can I then add and remove items from an immutable object to create new objects? Yes, although the new object is not frozen by default. Adding is quite straight forward, expecially with the spread syntax let x = { a: 1, b: 2 }; Object.freeze(x) let y = {...x, b: 3} // y == { a: 1, b: 3 } Removing is less intuitive let x = { a: 1, b: 2 }; Object.freeze(x) let { b, ...y} = x; // y == { a: 1 } > And the 'frozenness' isn't communicated through the language Yes, but given that JS is a dynamic language I wouldn't expect anything different (everything must inspected at runtime). > And freeze isn't recursive against the entire object graph You're right, although one could quickly implement a recursive version. In any case I find Object.freeze not much useful since trying to mutate a frozen object will simply ignore the operation; I think that most of the time trying to do that should be considered an error and I would prefer to have and exception raised.