That book you're reading is weird.
A primitive type has a fixed size in memory. For example, a number
occupies eight bytes of memory, and a boolean value can be represented
with only one bit. The number type is the largest of the primitive
types. If each JavaScript variable reserves eight bytes of memory, the
variable can directly hold any primitive value.
Reference types are another matter, however. Objects, for example, can
be of any length -- they do not have a fixed size. The same is true of
arrays: an array can have any number of elements. Similarly, a
function can contain any amount of JavaScript code. Since these types
do not have a fixed size, their values cannot be stored directly in
the eight bytes of memory associated with each variable. Instead, the
variable stores a reference to the value. Typically, this reference is
some form of pointer or memory address. It is not the data value
itself, but it tells the variable where to look to find the value.
And then the author goes on to explain how this causes different behaviour, as if that was an effect of the memory layout. But they've got that the wrong way round. The distinction should be:
- a primitive type has plain, immutable values, that will be copied by value when being passed around.
- a reference type - synonymous with "the object type" - has mutable objects as values, which have an identity (created when the object is instantiated) and can have arbitrary changeable properties. A variable never holds "an object" itself, but rather a reference to it, and it is this reference that is getting copied when you pass it around.
That (and "arrays and functions are objects") is the gist of the JavaScript value model. How this is implemented doesn't really matter - in fact it differs from engine to engine.
Now when you ask "Why string is a primitive?", the answer is "because strings are immutable values and don't have properties".