Understanding Javascript immutable variable
Values are immutable; variables are not; they hold a reference to their (primitive) values.
The three primitive types string, number and boolean have corresponding types whose instances are objects: String, Number, Boolean.
They are sometimes called wrapper types.
The following values are primitive:
- Strings: "hello"
- Numbers: 6, 3.14 (all numbers in JavaScript are floating point)
- Booleans: true, false
- null: usually explicitly assigned
- undefined: usually the default (automatically assigned) value
So:
- Objects are mutable by default
- Objects have unique identities and are compared by reference
- Variables hold references to objects
- Primitives are immutable
- Primitives are compared by value, they don’t have individual identities
Also, in ES6 there is a new const keyword, that creates a read-only named constant that cannot change value through assignment or be re-declared while the script is running.
Hope this helps!
How do I make a JavaScript variable completely immutable?
You can use Object.freeze
for this (obviously only on object
s).
const hello = Object.freeze(["hello", "world"]);
// hello.push("!!!");// will throw "TypeError: can't define array index property past the end of an array with non-writable length"
// hello.length = 0;// will fail silently
// hello.reverse();// will throw "TypeError: 0 is read-only"
// hello[0] = "peter";// will fail silently
Why is immutability so important (or needed) in JavaScript?
I have recently been researching the same topic. I'll do my best to answer your question(s) and try to share what I have learned so far.
Basically it comes down to the fact that immutability increases predictability, performance (indirectly) and allows for mutation tracking.The question is, why is immutability so important? What is wrong in
mutating objects? Doesn't it make things simple?
Predictability
Mutation hides change, which create (unexpected) side effects, which can cause nasty bugs. When you enforce immutability you can keep your application architecture and mental model simple, which makes it easier to reason about your application.
Performance
Even though adding values to an immutable Object means that a new instance needs to be created where existing values need to be copied and new values need to be added to the new Object which cost memory, immutable Objects can make use of structural sharing to reduce memory overhead.
You can read more about this here.All updates return new values, but internally structures are shared to
drastically reduce memory usage (and GC thrashing). This means that if
you append to a vector with 1000 elements, it does not actually create
a new vector 1001-elements long. Most likely, internally only a few
small objects are allocated.
Mutation Tracking
Besides reduced memory usage, immutability allows you to optimize your application by making use of reference- and value equality. This makes it really easy to see if anything has changed. For example a state change in a react component. You can use shouldComponentUpdate
to check if the state is identical by comparing state Objects and prevent unnecessary rendering.
You can read more about this here.
Additional resources:
- The Dao of Immutability
- Immutable Data Structures and JavaScript
- Immutability in JavaScript
Yes this is correct. If you're confused on how to implement this in your application I would recommend you to look at how redux does this to get familiar with the core concepts, it helped me a lot.If I set say an array of objects with a value initially. I can't
manipulate it. That's what immutability principle says, right?(Correct
me if I am wrong). But, what if I have a new News object that has to
be updated? In usual case, I could have just added the object to the
array. How do I achieve in this case? Delete the store & recreate it?
Isn't adding an object to the array a less expensive operation?
I like to use Redux as an example because it embraces immutability. It has a single immutable state tree (referred to as store
) where all state changes are explicit by dispatching actions which are processed by a reducer that accepts the previous state together with said actions (one at a time) and returns the next state of your application. You can read more about it's core principles here.
There is an excellent redux course on egghead.io where Dan Abramov, the author of redux, explains these principles as follows (I modified the code a bit to better fit the scenario):
import React from 'react';
import ReactDOM from 'react-dom';
// Reducer.
const news = (state=[], action) => {
switch(action.type) {
case 'ADD_NEWS_ITEM': {
return [ ...state, action.newsItem ];
}
default: {
return state;
}
}
};
// Store.
const createStore = (reducer) => {
let state;
let listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(cb => cb !== listener);
};
};
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach( cb => cb() );
};
dispatch({});
return { subscribe, getState, dispatch };
};
// Initialize store with reducer.
const store = createStore(news);
// Component.
const News = React.createClass({
onAddNewsItem() {
const { newsTitle } = this.refs;
store.dispatch({
type: 'ADD_NEWS_ITEM',
newsItem: { title: newsTitle.value }
});
},
render() {
const { news } = this.props;
return (
<div>
<input ref="newsTitle" />
<button onClick={ this.onAddNewsItem }>add</button>
<ul>
{ news.map( ({ title }) => <li>{ title }</li>) }
</ul>
</div>
);
}
});
// Handler that will execute when the store dispatches.
const render = () => {
ReactDOM.render(
<News news={ store.getState() } />,
document.getElementById('news')
);
};
// Entry point.
store.subscribe(render);
render();
Also, these videos demonstrate in further detail how to achieve immutability for:- Arrays
- Objects
Successfully changed the Immutable or Primitive Data-Types in JS. Then How these are Primitives or is JS Concepts wrong?
You are not mutating the existing primitives. You're simply assigning new primitive values (which are immutable as well) to the existing variable names.
Mutation is not the same thing as variable name reassignment. Mutation looks something like the following:
someObj.someProp = newPropVal;
Reassignment is:someVarName = newVal;
Primitives don't have own-properties; trying to assign to a property of a primitive doesn't do anything and will throw an error in strict mode, because primitives are immutable.Here's one way of looking at it (it's a nice visualization, though it's necessarily an accurate reflection of what's actually happening in the bytecode): values reference a location in memory. Variable names point to locations in memory. Say that false
corresponds to memory location 1234, and you create an object {}
which corresponds to memory location 9999. You can assign false
to a variable name and have that variable name point to location 1234 in memory. You can reassign the value that the variable name points to by using location 9999 instead, that points to the object. The object, unlike the primitive, is a potential container for other values (and other memory locations). The primitive cannot act as such a container.
What does immutable mean?
It means that once you instantiate the object, you can't change its properties. In your first alert you aren't changing foo. You're creating a new string. This is why in your second alert it will show "foo" instead of oo.
Yes. Nothing can change the string once it is created. Now this doesn't mean that you can't assign a new string object to theDoes it mean, when calling methods on
a string, it will return the modified
string, but it won't change the
initial string?
str
variable. You just can't change the current object that str references.Technically, no, because the substring method returns a new string. Making an object mutable, wouldn't change the method. Making it mutable means that technically, you could make it so that substring would change the original string instead of creating a new one.If the string was mutable, does that
mean the 2nd alert() would return oo
as well?
Related Topics
How to Bind Bootstrap Popover on Dynamic Elements
Adding Code to a JavaScript Function Programmatically
How to Filter an Array in JavaScript
How to Parseint a String with Leading 0
How to Get the Focused Element with Jquery
How to Add a "Readonly" Attribute to an <Input>
JavaScript Array .Reduce with Async/Await
Rails 5: How to Use $(Document).Ready() with Turbo-Links
Angularjs Communication Between Directives
Get the Current Year in JavaScript
How Is a JavaScript Hash Map Implemented
How to Trigger Click on Page Load
Jquery:Select All Element with Custom Attribute
Why Duck Typing Is Allowed for Classes in Typescript
Differencebetween Decodeuricomponent and Decodeuri