Давайте ответим на вопрос, озвученный в начале: в зависимости от реализации, в JS значения разных типов могут по-разному представляться. Если рассмотреть движок V8, картина выглядит следующим образом (я буду использовать знак * для указателей, которые фактически ими не являются):
1. null - указатель* состоящий из одних нулевых битов, константа (объект, которого нет);
2. undefined - это тоже указатель*, содержащий константный набор бит, сигнализирующий об отсутствии значения;
3. boolean - два константных указателя* со значениями true и false;
4. string - указатель на строку в памяти (сама строка обычно хранится в куче, но это не всегда так);
5. Для строк в V8 есть несколько подтипов для операций, таких как конкатенация, срезы, внешние строки, и оптимизация для строк-литералов, состоящих только из символов ASCII;
6. number - если число целое и меньше чем 2 ** 31, то оно будет храниться в самом указателе* (SMI числа), а числа превышающие это объём или дробные уже будут храниться в другом месте, т.е. указатель в данном случае реально ссылается на данные.
7. bigint - т.к. bigint не ограничен каким то конкретным размером, а только доступной памятью, то он может храниться только в куче и адресоваться по указателю.
8. symbol - т.к. символы - это уникальные константные значения, которых может быть много, то в сам указатель их скорее всего не поместить.
9. object - тут все просто, т.к. все объекты всегда хранятся в куче и передаются по указателю.
И теперь финальный ответ на вопрос: все типы данных в JS представляются в виде указателей, но некоторые таковыми реально не являются. Т.е. типы, которые содержат сами данные в себе будут копироваться при передаче.
С другой стороны, строки и другие типы, которые нельзя сохранить в самом указателе просто так копироваться не будут. И да, исключая всякие хитрые оптимизации, нам не важно как именно они передаются, т.к. они все равно неизменяемы.
А вот напоследок вам вопрос:
1. null - указатель* состоящий из одних нулевых битов, константа (объект, которого нет);
2. undefined - это тоже указатель*, содержащий константный набор бит, сигнализирующий об отсутствии значения;
3. boolean - два константных указателя* со значениями true и false;
4. string - указатель на строку в памяти (сама строка обычно хранится в куче, но это не всегда так);
5. Для строк в V8 есть несколько подтипов для операций, таких как конкатенация, срезы, внешние строки, и оптимизация для строк-литералов, состоящих только из символов ASCII;
6. number - если число целое и меньше чем 2 ** 31, то оно будет храниться в самом указателе* (SMI числа), а числа превышающие это объём или дробные уже будут храниться в другом месте, т.е. указатель в данном случае реально ссылается на данные.
7. bigint - т.к. bigint не ограничен каким то конкретным размером, а только доступной памятью, то он может храниться только в куче и адресоваться по указателю.
8. symbol - т.к. символы - это уникальные константные значения, которых может быть много, то в сам указатель их скорее всего не поместить.
9. object - тут все просто, т.к. все объекты всегда хранятся в куче и передаются по указателю.
И теперь финальный ответ на вопрос: все типы данных в JS представляются в виде указателей, но некоторые таковыми реально не являются. Т.е. типы, которые содержат сами данные в себе будут копироваться при передаче.
С другой стороны, строки и другие типы, которые нельзя сохранить в самом указателе просто так копироваться не будут. И да, исключая всякие хитрые оптимизации, нам не важно как именно они передаются, т.к. они все равно неизменяемы.
А вот напоследок вам вопрос:
[1, 2, 3, 4, 5] // Это массив содержит сами числа или только ссылки на них?
[1.0, 5.4, 4.34] // А этот?
[1.0, 'foo', true, 10] // А этот?