42

I am trying to understand what a Javascript immutable variable means. If I can do:

var x = "astring";
x = "str";
console.log(x); //logs str` , then why it is immutable?

The only answer I can think (from the little bit of C I know) is that var x is a pointer to a memory block with the value "astring", and after the 2nd statement it points to another block with the value "str". Is that the case?

And a bonus question: I was confused by the value types of Javascript. Are all variables objects under the hood? Even number and strings?

zarathustra
  • 1,898
  • 3
  • 18
  • 38
Antonis Grigoriadis
  • 2,060
  • 2
  • 16
  • 26
  • 1
    Duplicate: http://stackoverflow.com/questions/3200211/what-does-immutable-mean – timss Apr 20 '13 at 01:14
  • 1
    i have seen that post. But I don't just call a method. I assign a new value. Is that the same? – Antonis Grigoriadis Apr 20 '13 at 01:16
  • 1
    Assigning a new value does exactly that: assigns a new value. You haven't modified a string, you've changed a reference. Yes, variables reference objects: `"hi there".split()` or `typeof 5` for example. – Dave Newton Apr 20 '13 at 01:18
  • Your "bonus question" should be asked separately, assuming it hasn't been already. – intuited Apr 20 '13 at 01:24

6 Answers6

60

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!

Mouneer
  • 12,827
  • 2
  • 35
  • 45
GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
  • Thanks it helps. But I don't know what unique identity is.. Also, can I find more analytical info about how primitives are associated with these wrappers? Just seems strange to me that i can call a method on primitives (eg aString.length). – Antonis Grigoriadis Apr 20 '13 at 01:56
  • 1
    The ***wrapper*** has the method `length`. Note the casing in the second line of my answer.     This [link: The Secret Life of JavaScript Primitives](http://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/) might help a lot! – GitaarLAB Apr 20 '13 at 02:00
  • 2
    So, if I have understood it correctly, then in contrast to C, in JavaScript, if you have a memory location referenced to by say, var x = 1; having the content 0000000000000001 then **"immutability"** implies that we can't change the memory lcoation's contents to say, 0000000000000011. If this is the case then, if I write var x=1; x=2; everytime JavaScript will provide me with a new memory location and garbage-collect the older unattended one? – Manish Kumar Sharma Jun 08 '15 at 09:36
  • 1
    @pulp_fiction: yes, as long as no other other 'var' 'references' that 'value'. However, I'd like to note that in real life, modern browsers do all kinds of optimizations, like not all numbers are in fact floating, small integers are superfast (hinting they are not 32bit internally either), observing and re-compiling sections of code (depending on actual usage), etc, etc. Extra note: If you'd have an arraybuffer however, one can overwrite a specific address inside that buffer, making them more predictable (in terms of actual memory-load on the cpu running the script). – GitaarLAB Jun 09 '15 at 14:11
  • @ChrisAnderson: reference `a` (in your example) points to an Object (aka the 'value' of `a` is an Object, if you will). You did **not** [freeze](https://stackoverflow.com/a/21402679/588079) the Object, thus you can add/remove/modify the Object's properties/methods ('content' if you will) and even it's prototype! Therefore, your example (`const a = {}; a.b = 1; a.b === 1`) *does exactly what it's supposed to do*. However, if you had posted `const a = {}; a = 42;`, then *that should throw `Uncaught SyntaxError`*. – GitaarLAB Jun 12 '18 at 06:11
22

First, in C "A string is an array of characters with last elem = '\0' ". They are mutable.
If you declare and initialize a string in C like this:

char str[] = "Foo";

What you are basically doing is reserving 4 bytes ( probably 8bit-byte, don't mind this probably if it hurts you ). The word str serves as a pointer to the first elem of this array. So, if you do like this:

str[0] or *(str) = 'G'

then it will mutate the value at that address instead of creating new array. You can verify it by printing out the address of str. In both cases it will be same.

Now in case of JavaScript string is a primitive type. All operations on string are done by value instead of by reference. So, doing this will produce true.

var str1 = "foo";
var str2 = "foo";
str1 === str2; => true

The initialization of string asks for a buffer to fit "foo" and binds the name str1 to it. What makes them immutable is that you can't change that buffer. So, you can't do this:

str1[0] = 'G'

Executing this command will produce no warning or error in non-strict mode but, it will not change the str1. You can verify it by

console.log(str1) => "foo"

But if you do like this:

str1 = "goo"

what you are actually doing is that you are asking for a new buffer to fit "goo" and bind identifier str1 to it. No change in that old buffer containing "foo".

So, what happens to "foo"?

Java Script has an automatic garbage collector. When it sees some chunk of memory that no longer can be referenced by any identifier or ... then it consider that memory free.

Same happens to number,booleans. Now, about wrapper objects! Whenever you try to access a property on string like this:

str1.length;

What JavaScript does it creates a new object using String class and invoke the methods on string. As soon as the function call returns, the object is destroyed. The below code explains it further:

var str = "nature"; 
str.does = "nurtures"; //defining a new property; 
console.log(str.does) => undefined

because the object has been destroyed. Try this!

var str = new String("Nature");
str.does = "nurtures";
console.log(str) =>  ??

this str is really an object...

Conclusion: In C , in a single scope the variable name serves as a pointer. So, int, float, string all are mutable. But in Java Script a primitive type variable name serves as value not as reference

References: C++ primer plus, Java Script The Definitive Guide, C by Stephen Kochan

aMother
  • 893
  • 8
  • 19
  • "All operations on string are done by value instead of by reference" I'm confused. Isn't a string really a reference to a buffer? – Le Curious Apr 03 '14 at 20:46
  • 1
    @LeCurious In C if you do like this char str[] = "foo". Then str will be a reference (pointer) to the buffer. You can make changes to that buffer using this reference. But, in javaScript if you do this var str = "hi". Then str is an read-only identifier which is used to access the buffer where hi is stored. – aMother Apr 07 '14 at 19:14
  • @LeCurious Yes you can say in javascript we have a reference to a read only buffer while in C we have reference to readwrite buffer. Hope you have got the jest :) – aMother Apr 19 '14 at 17:17
5

You are correct. Strings (and numbers) are immutable in java script (and many other languages). The variables are references to them. When you "change the value of a variable" you are changing the string (or whatever) that the variable references, not the value itself.

CBass
  • 983
  • 6
  • 11
  • I think I m starting to understand, thanks. Do you know what happens to the first value (in my example "astring")? It exists in memory until the garbage collector pass? – Antonis Grigoriadis Apr 20 '13 at 01:41
5

I think many new programmers believe immutability to mean that primitive values cannot be changed by reassignment.

var str = "testing";
var str = "testing,testing";
console.log(str); // testing, testing

var fruits = ["apple", "banana", "orange"];

fruits[0] = "mango";

console.log(fruits); //["mango", "banana", "orange"]

The values associated with both mutable and immutable types can be changed through reassignment as the above examples with strings and arrays show. But then, these data types have associated functions(methods) that are used to manipulate the values belonging to each data type. This is where mutability/immutability is seen. Since arrays are mutable, any manipulation by an array method affects the array directly. For example,

var fruits = ["mango","banana", "orange"];
fruits.pop(); 
console.log(fruits) //["mango", "banana"]


The array.pop() method deleted "orange" from the original fruits array.
But with strings for example,


var name = "Donald Trump";
name.replace("Donald", "President");
console.log(name)//Donald Trump

the original string remains intact!

Immutability disallowed any altering of the original string by the string method. Instead, the method produces a new string if the method operation is assigned to a variable like so:

var name = "Donald Trump";
var newName = name.replace("Donald", "President");
console.log(newName);//President Trump
webAfrique
  • 51
  • 1
  • 3
  • Of note, the last example works using `name` instead of `var newName`, but it works the same way assigning a new buffer. The old buffer "Don..." remains until garbage collection takes care of it. – aamarks Jun 13 '19 at 16:29
1

Let's understand here, first,

let firstString = "Tap";

console.log(firstString);  //Output: Tap 

firstString[0] = "N";

console.log(firstString)   //Output: Tap

This is where we can see the immutable effect!

Amal K
  • 4,359
  • 2
  • 22
  • 44
Gayatri
  • 121
  • 1
  • 2
0

Immutability in this definition is historic. It's attached to what could be done in OTHER programming languages.

I think that is the first thing to understand. And to programmers who have only used JavaScript the question may seem nonsensical or needlessly pedantic. Describing primitives as immutable is like describing ice cream as not being able to jump. Why would I think it could? It is only in relation to other historic programming languages that the lack of mutability is apparent when dealing with primitive types.