Сегодня мы рассмотрим тему «Объекты как ссылочные типы«, но для начала вот список статей на тему «Объекты в JavaScript»:
Объекты как ссылочные типы
Все типы данных JavaScript можно разделить на примитивные и ссылочные. Эти два класса соответствуют примитивным и составным типам данных, обсуждению которых была посвящена ранее. Примитивные типы данных это: числовой, строковый, логический, неопределенный и пустой. Эти типы примитивны в том смысле, что они ограничены множеством конкретных значений. Можно понимать примитивные данные как те, что сохраняются непосредственно в переменной. Ссылочные типы — это объекты, включая Object, Array и Function. Ввиду того что эти типы могут содержать очень большие объемы весьма разнородных данных, переменная, содержащая ссылочный тип, фактически его значения не содержит. Она содержит ссылку на место в памяти, где размещаются реальные данные.
Со временем это различие станет вам понятным. Но в некоторых ситуациях нужно обращать особое внимание на следствия, вытекающие из применения указанных типов. Такая ситуация возникает, например, тогда, когда вы создаете две ссылки на один и тот же объект. Рассмотрим следующий пример с примитивными типами:
1 2 3 4 |
var х = 10; var у = х; х = 2; alert("Значением у является: " + y); |
Этот программный код ведет себя так, как и следует ожидать. Ввиду того что переменная х имеет примитивный тип (числовой), сохраненное в ней значение (10) присваивается переменной у во второй строке. Изменение значения х никак не влияет на у, потому что переменная у получила копию значения х.
Результатом будет: Значением является: 10
Теперь рассмотрим аналогичный код с использованием ссылочного типа:
1 2 3 4 |
var х = [10, 9, 8] ; var у = х; х[0] = 2; alert("Значением первого элемента у является: " + у[0]); |
Результат может показаться неожиданным: Значением первого элемента у является: 2
Массивы являются ссылочными типами, поэтому вторая строка копирует ссылку на данные х в переменную у. Теперь и х, и у ссылаются на одни и те же данные, так что изменение значения этих данных с помощью переменной естественно оказывается видимым как для х, так и для у.
Передача объектов функциям
Другая ситуация, когда следует уделять особое внимание ссылочным типам, возникает при передаче их в виде аргументов функциям. Вспомните (глава 5), что аргументы передаются функциям по значению. Ввиду того что ссылочные типы содержат ссылки на соответствующие реальные данные, аргументы функции получают копию ссылки на данные и могут, таким образом, менять оригинальные данные. Этот эффект иллюстрируется следующим примером, в котором два значения — примитивного и ссылочного типов — передаются функции, изменяющей их данные:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Определение ссылочного типа (массив) var refType = ["первый ", " второй", " третий"]; // Определение примитивного типа (число) var primType = 10; // Определение функции с двумя аргументами, которые она модифицирует function modifyValues(ref, prim) { ref[0] = "измененный"; // модифицирует первый аргумент (массив) prim = prim - 8; // модифицирует второй аргумент (число) } // Вызов функции modifyValues(refType, primType); // Печать значения ссылочного типа document.writeln("Значением refType является: ", refType+"<br />"); // Печать значения примитивного типа document.writeln("Значением primType является: ", primType); |
Результатом будет:
- Значением refType является: измененный, второй, третий
- Значением primType является: 10;
Сравнение объектов
Еще одна ситуация, когда следует быть осторожным со ссылочными типами (объектами), возникает при их сравнении. При использовании операции проверки равенства (==) интерпретатор сравнивает значения соответствующих переменных. Для примитивных типов это означает сравнение фактических данных:
1 2 3 |
var strl = "abc"; var str2 = "abc"; alert(strl == str2); |
Результат соответствует ожиданиям: true
В случае ссылочных типов переменные содержат ссылки на данные, а не сами данные. Поэтому при использовании операции проверки равенства происходит сравнение ссылок, а не объектов, на которые эти ссылки указывают. Другими словами, операция == обеспечивает проверку не того, что две переменные ссылаются на эквивалентные объекты, а того, что переменные ссылаются на один и тот же объект. Для иллюстрации рассмотрим
1 2 3 |
var str1 = new String("abc"); var str2 = new String("abc"); alert(strl == str2); |
Результат может показаться неожиданным: false Даже если объекты, на которые ссылаются str1 и str2, эквивалентны, это не один и тот же объект, поэтому результатом сравнения является значение false (ЛОЖЬ).
Здесь возникает следующий вопрос: если нельзя проверить равенство двух объектов с помощью == для их ссылок, то как это сделать? Имеются два способа: с помощью преобразования объектов к примитивному типу или с помощью специально созданной для этого функции.