As @JörgWMittag, says, the spec does not tell us, except that there is no explicit free operation, so sometimes there will be no choice but automatic memory management (e.g. garbage collection).
JavaScript defines the following:
A primitive value is a member of one of the following built-in types: Undefined, Null, Boolean, Number, String, and Symbol
Undefined, Null, Boolean, and Number all have fixed sized format. Number, for example, is defined in terms of IEEE 64-bit floating point. It is most likely that for local variables, these fixed sized formats are represented directly on the stack rather than being heap allocated. JavaScript variables, however, are not typed the way Java variables are, so these variables can change their types during execution, meaning that sometimes the program will do something that asks what type the variable is, sometimes requiring the runtime to dynamically store the type as well as the value. Still, that information is also probably fixed in size (e.g. a pointer), meaning even the combination of type and Number, for example, could be stored in a fixed size, stack allocated storage.
JavaScript transfers these primitive types by copying; it does not provide a reference-to-primitive mechanism (which would complicate storage management for them). However, it does have closures, and they capture variables not values. This means that sometimes local variables have to outlive their local scope, which suggests that for them the heap is necessarily used.
The String type, on the other hand, probably involves dynamic heap allocation, since strings can, for example, be dynamically-sized temporary values generated in a called function and returned to the caller. There are probably be situations where strings are not heap allocated (e.g. literals), and thus not garbage collected.
Java, on the other hand, defines specific sized primitive types, and String is not one of them (String is an object type).