Формат JSON предназначен для сериализации структур данных и может использоваться для представления простых значений, массивов и простых объектов. При преобразовании в этот формат не делается никаких предположений о классах, и при сериализации объекта игнорируются его прототип и конструктор. Если вызвать функцию
JSON.stringify
для сериализации объекта
Range
или
Complex
, например, она вернет строку вида
{"from”: 1, ”to":3}
или
{"r":1, "i":-1}.
Если передать такую строку функции
JSON.parse,
она вернет простой объект со свойствами, соответствующими объекту
Range
или
Complex
, но не наследующий методы класса
Range
или
Complex
.
Такой формат сериализации вполне подходит для классов, таких как
Range
и
Complex
, но для более сложных классов может потребоваться написать собственный метод
toJSON,
чтобы определить иной формат сериализации. Если объект имеет метод
toJSON,
функция
JSON.stringify
не будет выполнять сериализацию самого объекта, а вызовет метод
toJSON
и произведет сериализацию значения (простого значения или объекта), которое он вернет. Например, объекты
Date
имеют собственный метод
toJSON,
возвращающий строковое представление даты. Типы-перечисления в примере 9.7 делают то же самое: их метод
toJS0N
возвращает то же значение, что и метод
toString.
Самым близким к представлению множества в формате JSON является массив, поэтому ниже мы определим метод
toJSON,
который будет преобразовывать объект
Set
в массив значений.
Класс
Set
, представленный в примере 9.6, не определяет ни один из этих методов. Множество не может быть представлено простым значением, поэтому нет смысла определять метод
valueOf,
но было бы желательно определить в этом классе методы
toString, toLocaleString
и
toJSON.
Можно это сделать, как показано ниже. Обратите внимание, что для добавления методов в
Set.prototype
используется функция
extend
(пример 6.2):
// Добавить новые методы в объект-прототип класса Set.
extend(Set.prototype, {
// Преобразует множество в строку
toString :
function {
var s = "{", i = 0;
this.foreach(function(v){ s += ((i++ > 0)?", + ":"") +v });
return s + "}";
}
// Действует так же, как toString, но вызывает toLocaleString
// для всех значений
toLocaleString :
function {
var s = "{",
і = 0;
this.foreach(function(v){
if (i++ > 0)
s += ", ";
if (v == null) s += v; // null и undefined
else s += v. toLocaleString; // остальные
});
return s +
},
// Преобразует множество в массив значений
toArray :
function {
var a = [];
this.foreach(function(v) { a.push(v); });
return a;
}
});
// Для нужд сериализации в формат JS0N интерпретировать множество как массив.
Set.prototype.toJSON = Set.prototype.toArray;
9.6.4. Методы сравнения
Операторы сравнения в языке JavaScript сравнивают объекты по ссылке, а не по значению. Так, если имеются две ссылки на объекты, то выясняется, ссылаются они на один и тот же объект или нет, но не выясняется, обладают ли разные объекты одинаковыми свойствами с одинаковыми значениями.[17] Часто бывает удобным иметь возможность сравнить объекты на равенство или определить порядок их следования (например, с помощью операторов отношения
<
и
>
). Если вы определяете новый класс и хотите иметь возможность сравнивать экземпляры этого класса, вам придется определить соответствующие методы, выполняющие сравнение.
В языке программирования Java сравнение объектов производится с помощью методов, и подобный подход можно с успехом использовать в JavaScript. Чтобы иметь возможность сравнивать экземпляры класса, можно определить метод экземпляра с именем equals. Этот метод должен принимать единственный аргумент и возвращать true, если аргумент эквивалентен объекту, метод которого был вызван. Разумеется, вам решать, что следует понимать под словом «эквивалентен» в контексте вашего класса. Для простых классов часто достаточно просто сравнить свойства constructor, чтобы убедиться, что оба объекта имеют один и тот-же тип, и затем сравнивать свойства экземпляра двух объектов, чтобы убедиться, что они имеют одинаковые значения. Класс
Complex
из примера 9.3 как раз обладает таким методом
equals,
и для нас не составит труда написать похожий метод для класса
Range
:
// Класс Range затирает свое свойство constructor. Поэтому восстановим его.
Range.prototype.constructor = Range;
// Объект Range не может быть равен никакому другому объекту, не являющемуся
// диапазоном значений. Два диапазона равны, только если равны значения их границ.