I know that String primitive type in Javascript is immutable, via practice and word of mouth. But what combination of rules in the ECMA-262 makes it so? More specifically, why the second line in the following example silently does nothing?
const str = 'abc';
str[1] = '8';
console.log(str); // prints unmodified "abc", not "a8c".
Section 6.1.4 describes the internal composition of String datum. It does not contain anything about modifying the data, or at least I couldn't find anything after reading it thrice.
Section 13.15.2 describes the semantics of assignment. It does not contain any exceptions for any specific data type.
Section 13.3.2.1 describes the semantics of the property accessor operator. It does not contain any exceptions for any specific data type.
So, how exactly the string data type is defined to be immutable in Javascript?
The EMCAScript specification is silent about this, just as it is silent on object identity (i.e. object mutability). So yes, it's more about "via practice and word of mouth", but I guess a conforming implementation could change the memory representation of a string in the background (or even provide an API to do so as an extension).
However, you can infer the immutability of strings from the phrasing of §6.1.4 "The String Type" that you linked:
This is a very mathematical definition, and in mathematics, values are always immutable. In addition, we can observe that there simply is no operation within ECMAScript that would mutate such a value.
The definition applies only to primitive values though, not to
String
objects which wrap such a value and can have additional (mutable) properties. Again, there just is no operation that would change the [[StringData]] internal slot of aString
instance. This is even explicitly described in the section on String Exotic Objects:This is also what you observe in your example code. The assignment
str[1] = …
goes to String's [[DefineOwnProperty]] internal method, which finds that the1
property is non-writable, rejecting a change. The PutValue abstract operation will then throw an exception in strict mode (or ignore the failure in sloppy mode).