Why Composite Data Types are Copied by Reference but Primitives by Value?
JavaScript offers a bunch of built-in data types and these data types are called primitive data types. Number, String, Boolean, BigInt, undefined and Symbol are the 6 primitive data types available in JavaScript. These primitive data types are immutable by default and are often passed by value i.e a different copy with the same value is created in the memory and is assigned to the new variable to which it is being passed.
Just like any other object-oriented programming language JavaScript also offers to create data-structures of your own and these are often called as user-defined data types or composite data types. These data types are necessary for imitating real-life objects in some cases and also for the ease of usability and efficiency. Objects and Array are the most basic composite data type and could get as complex as you want. The most important thing to note here is that composite data types are mutable i.e they can be modified.
WHY the Difference?
The key difference is in how they are stored in the memory. Locally defined primitive types are stored on a stack whereas, those defined as part of an object are stored in heap. Also, as mentioned before primitive types are immutable and composite types are mutable. This is simply because primitive data types are responsible for storing values which are universal and constant. Say for example the number 5, the number 5 will always be a number 5, a number 6 cannot mean number 5.
On the other hand, composite data types can have a collection of different primitive types and/or composite types. And since composite types are mutable, when we copy the data stored in one object to another by referencing it directly, it points to the same reference in the heap and any manipulation in that data would affect the data in both the variables referencing that data.