Understanding JavaScript Immutable Variable

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

All other values are objects, including wrappers for primitives.

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

You might find The Secret Life of JavaScript Primitives a good explanation.

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 objects).

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.

The question is, why is immutability so important? What is wrong in
mutating objects? Doesn't it make things simple?

Basically it comes down to the fact that immutability increases predictability, performance (indirectly) and allows for mutation tracking.

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.

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.

You can read more about this here.

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

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?

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.

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.

Does it mean, when calling methods on
a string, it will return the modified
string, but it won't change the
initial string?

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 the str variable. You just can't change the current object that str references.

If the string was mutable, does that
mean the 2nd alert() would return oo
as well?

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.



Related Topics



Leave a reply



Submit