Строки: переменные примитивного типа или переменные ссылочного типа в javascript?

#javascript #string

#javascript #строка

Вопрос:

Сегодня я снова читал свою книгу по javascript, и в ней объяснялась разница между переменными ссылочного типа и переменными примитивного типа. Он привел эти примеры, чтобы проиллюстрировать разницу.

Пример 1 (примитивный тип)

 var a = 3.14;
var b = a;
a = 4;
alert( b ); // Displays 3.14
  

Пример 2 (ссылочный тип)

 var a = [1, 2, 3];
var b = a;
var a[0] = 99;
alert( b ); // Displays the changed array [99, 2, 3]
  

Я понимаю этот пример, и у меня нет никаких вопросов по этому поводу. Мой вопрос касается строк в javascript. Интуитивно я бы предположил, что строки являются переменными ссылочного типа, потому что если динамический размер, но я возился с ними на example.com и я создал этот пример, который, кажется, указывает на то, что строки являются переменными примитивного типа.

Пример 3 (строки?)

 var a = 'Ben';
var b = a;
var a = 'Benjamin';
alert( b ); //Displays the unchanged 'Ben'
  

Я искал здесь, в stack overflow и в Google, и я нашел несколько статей, в которых говорилось об этом, но большинство из них говорили о других языках, таких как Java и C #.

Вопрос:
В javascript строки считаются примитивными или ссылочными типами переменных и существуют ли какие-либо другие ситуации, о которых я должен знать, когда строки работают иначе, чем я ожидал?

Комментарии:

1. Если вы попробуете пример 3 с массивом ['B','e','n'] , вы получите те же результаты — когда вы присваиваете a переменной новое значение (другой массив), которое не влияет b . Попробуйте пример 2 (где вы изменяете 0 поле a ) с помощью строки — это вызовет исключение.

Ответ №1:

Нет. В JavaScript строки неизменяемы и, следовательно, являются примитивным типом.

То, что они имеют переменные размеры, похоже на числа разной величины. Их размер не является динамическим, вы не можете изменить размер существующего строкового значения. Всякий раз, когда вы выполняете операции со строками, вы создаете новые значения. Точно так же, как var x = 1; x = 2 не изменит 1 значение (но создаст новое 3 значение), var var a = "Hi!"; a = "!" не изменит строку "Hi!" .

Комментарии:

1. var a = "Hi!"; a = "!"; Вы можете добавлять символы в строку, чтобы их размер мог изменяться, но вы не можете сделать, скажем a[2] = "?" .

2. Хотя это, вероятно, зависит от выбора реализации в движке JS, строки, скорее всего, передаются по ссылке (например, при передаче другим пользователям той же строки копия не создается), но поскольку они неизменяемы и данная строка никогда не может быть изменена, они в конечном итоге ведут себя скорее как примитивы.

3. @NobleMushtak — это не совсем правильно. Когда вы «изменяете» строку, создается новая строка. Исходная строка никогда не изменялась. Попробуйте это: var a = "Hi!"; var b = a; a = "!"; . Теперь посмотрите на b и a . Они отличаются, показывая вам, что строка в a на самом деле не была изменена, но с изменением в ней была создана новая строка.

4. @NobleMushtak: Нет, вы не добавляете символ. Вы создаете новую строку путем объединения Hi! и ! , которые затем присваиваете a переменной. И да, вы не можете назначить a[2] .

5. Хм … ХОРОШО. Спасибо за разъяснение. Извините за отклонение вашего ответа. @jfriend00

Ответ №2:

Когда вы это делаете a = 'Benjamin' , оператор присваивания ( = ) изменяет объект, на который a указывает. Это не меняет того, на какой объект указывают другие переменные. Чтобы проиллюстрировать:

 var a, b;

a = "Ben";      // `a` now points to "Ben" in memory
b = a;          // `b` now points to "Ben" in memory
a = "Benjamin"; // `a` now points to "Benjamin" in memory, but
                // `b` still points to "Ben" 
  

Это не имеет ничего общего со строками; семантика одинакова для любого значения примитива или объекта.

Важная часть ответа на ваш вопрос, как указывает Берги, заключается в том, что строки в JavaScript неизменяемы, и поэтому независимо от реализации они действуют, по сути, как примитивы. Опять же, для иллюстрации:

 a = "Ben";    // `a` now points to "Ben" in memory
b = a;        // `b` now points to "Ben" in memory
a  = "jamin"; // `a` now points to "Benjamin" in memory, but
              // `b` still points to "Ben"
  

a = "jamin" , который, как вы знаете, эквивалентен a = a "jamin" , не изменяет строку, на которую указывают a и b ; он создает новую строку со значением "Benjamin" и делает a точку на нее вместо "Ben" . (Разделяют ли "Ben" и "Benjamin" одни и те же байты в памяти или нет, является деталью реализации, которая полностью непрозрачна для программы JavaScript.)

Комментарии:

1. Вопрос скорее в том, разделяют ли "Ben" (in a ) и "Ben" (in b ) общие байты в памяти… Дело в том, что они этого не делают с точки зрения JavaScript, и что он даже не знает о чем-то вроде «объекта последовательности байтов» в «памяти».

2. @Bergi Я думаю, мы с вами только что сказали одно и то же.

3. Ах, верно, я только что сослался на состояние после b = a; присвоения. На самом деле не понял, что "jamin" добавляет к объяснению…

Ответ №3:

В JavaScript строки являются примитивами.

Однако есть одна вещь, о которой вам следует знать. Объекты-оболочки. примитивы, такие как строки, числа, логические значения, оборачиваются в объекты, поэтому вы можете вызывать свойства для этих объектов-оболочек для удобства:

 var foo = 'bar';
var poo = foo.slice(0,-1)
poo == 'ar'; //true
  

Здесь строка ‘bar’ заключена в объект, который имеет метод slice (и многие другие), Но во всех других случаях (когда вы просто передаете примитивные переменные и т.д.) Переменная является просто примитивом.

Комментарии:

1. Объект-оболочка «создан» только для поиска свойства (которое движок оптимизирует), вы не можете его наблюдать (если только в неаккуратном режиме)

2. что вы имеете в виду, «наблюдая» за этим?

3. Вы не можете зарегистрировать это, показать это, использовать это… Все, что он делает, это предоставляет свойство, вы никогда не видите фактический объект-оболочку (в вашем примере). Нет причин что-либо осознавать.

Ответ №4:

Пример 3 не работает, потому что, как сказал Джордан, если вы измените значение фактического объекта, а не просто свойства, объекты, на которые указывает object, не изменятся, даже если object является ссылочным типом в JavaScript.

Однако строки являются неизменяемыми и примитивными значениями, поэтому, даже если мы сделали что-то вроде этого:

 var a = "Hi!";
var b = a;
a[2] = "?";
alert(a);
alert(b);
  

a все равно было бы, "Hi!" потому что строки неизменяемы, и b все равно было бы, "Hi!" даже если a было "Hi?" , потому что строки являются примитивными значениями.