Копирование по значению или по ссылке

Между простыми значениями (undefined, null, логическими значениями, числами и строками) и объектами (включая массивы и функции) в языке JavaScript имеются фундаментальные отличия.

Простые значения являются неизменяемыми: простое значение невозможно изменить (или «трансформировать»). Это очевидно для чисел и логических значений – нет никакого смысла изменять значение числа. Однако для строк это менее очевидно. Поскольку строки являются массивами символов, вполне естественно было бы ожидать наличие возможности изменять символы в той или иной позиции в строке. В действительности JavaScript не позволяет сделать это, и все строковые методы, которые, на первый взгляд, возвращают измененную строку, на самом деле возвращают новое строковое значение.

Например:

var s = "hello"; // Из­на­чаль­но име­ет­ся не­ко­то­рый текст из строч­ных сим­во­лов

s.toUpperCase(); // Вер­нет "HELLO", но зна­че­ние s при этом не из­ме­нит­ся
s // => "hello": ори­ги­наль­ная стро­ка не из­ме­ни­лась

Кроме того, величины простых типов сравниваются по значению: две величины считаются одинаковыми, если они имеют одно и то же значение. Для чисел, логических значений, null и undefined это выглядит очевидным: нет никакого другого способа сравнить их. Однако для строк это утверждение не выглядит таким очевидным. При сравнении двух строковых значений JavaScript считает их одинаковыми тогда и только тогда, когда они имеют одинаковую длину и содержат одинаковые символы в соответствующих позициях.

Объекты отличаются от простых типов.
Во-первых, они являются изменяемыми – их значения можно изменять:

var o = { x:1 }; // На­чаль­ное зна­че­ние объ­ек­та

o.x = 2; // Из­ме­нить, из­ме­нив зна­че­ние свой­ст­ва
o.y = 3; // Из­ме­нить, до­ба­вив но­вое свой­ст­во

var a = [1,2,3] // Мас­си­вы так­же яв­ля­ют­ся из­ме­няе­мы­ми объ­ек­та­ми

a[0] = 0; // Из­ме­нить зна­че­ние эле­мен­та мас­сив
a[3] = 4; // До­ба­вить но­вый эле­мент

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

var o = {x:1}, p = {x:1}; // Два объ­ек­та с оди­на­ко­вы­ми свой­ст­ва­ми
o === p // => false: раз­ные объ­ек­ты не яв­ля­ют­ся рав­ны­ми

var a = [], b = []; // Два раз­лич­ных пус­тых мас­си­ва
a === b // => false: раз­лич­ные мас­си­вы не яв­ля­ют­ся рав­ны­ми

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

var a = []; // Пе­ре­мен­ная a ссы­ла­ет­ся на пус­той мас­сив.
var b = a; // Те­перь b ссы­ла­ет­ся на тот же мас­сив.

b[0] = 1; // Из­ме­не­ние мас­си­ва с по­мо­щью ссыл­ки в пе­ре­мен­ной b.
a[0] // => 1: из­ме­не­ние мож­но на­блю­дать в пе­ре­мен­ной a.
a === b // => true: a и b ссы­ла­ют­ся на один и тот же объ­ект, по­это­му они рав­ны.

Как следует из примера выше, операция присваивания объекта (или массива) переменной фактически присваивает ссылку: она не создает новую копию объекта. Если в программе потребуется создать новую копию объекта или массива, необходимо будет явно скопировать свойства объекта или элементы массива. Следующий пример демонстрирует такое копирование с помощью цикла for:

var a = ['a','b','c']; // Ко­пи­руе­мый мас­сив
var b = []; // Мас­сив, ку­да вы­пол­ня­ет­ся ко­пи­ро­ва­ние

for(var i = 0; i < a.length; i++) { // Для ка­ж­до­го эле­мен­та в мас­си­ве a[]
 b[i] = a[i]; // Ско­пи­ро­вать эле­мент a[] в b[]
}

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

function equalArrays(a,b) {
 if (a.length != b.length) return false; // Мас­си­вы раз­ной дли­ны не рав­ны

 for(var i = 0; i < a.length; i++) // Цикл по всем эле­мен­там
   if (a[i] !== b[i]) return false; // Ес­ли хоть один эле­мент от­ли­ча­ет­ся, мас­си­вы не рав­ны

 return true; // Ина­че они рав­ны
}

results matching ""

    No results matching ""