Разработка и Конфигурация · 10 мин
Что такое значение объекта в 1С и с чем его едят
Разбираем, что такое значение объекта в 1С: разница между ссылкой и объектом, метод Значение(), приведение типов и типичные ошибки разработчиков.
Во встроенном языке 1С слово «значение» встречается в нескольких разных смыслах, и именно это путает начинающих разработчиков. Иногда под значением понимают содержимое переменной вообще, иногда — результат метода Значение(), который превращает один тип данных в другой, а иногда — «значение объекта» в противовес «ссылке на объект». Чтобы писать рабочий код, нужно чётко различать эти случаи.
Ключевой конфликт выглядит так: в переменной лежит ссылка на элемент справочника, а разработчик пытается изменить его реквизит напрямую и получает ошибку. Или наоборот — метод передаётся по значению, разработчик ждёт, что изменения сохранятся в исходной переменной, а они теряются. И то и другое — следствие непонимания, что в 1С есть значимые типы (передаются по значению) и ссылочные типы (передаются по ссылке).
Материал разбирает, что такое значение объекта в 1С, как ссылка отличается от объекта, зачем нужен метод Значение(), как работает передача параметров и какие ошибки в этой теме допускают чаще всего.
Что вообще называют значением в языке 1С
В широком смысле значение — это любые данные, хранящиеся в переменной: число, строка, дата, булево, ссылка, массив, структура. Каждая переменная в 1С содержит значение определённого типа, и тип этот не фиксируется при объявлении: одна и та же переменная может последовательно хранить строку, потом число, потом ссылку на документ.
Все типы данных в 1С делятся на две большие группы по способу хранения и передачи. Значимые типы (число, строка, дата, булево, массив, структура) при присваивании копируются целиком: после Б = А; переменные живут независимо, и изменение одной не затрагивает другую. Ссылочные типы (ссылки на справочники, документы, объекты, таблицы значений) при присваивании копируют только указатель: обе переменные смотрят на одни и те же данные.
Это различие фундаментально. Когда говорят «значение объекта», обычно имеют в виду данные, которые находятся по ссылке, — в противоположность самой ссылке, которая является лишь адресом. Понимание этой пары «ссылка — значение» снимает большинство вопросов.
Ссылка и объект: в чём разница
Ссылка — это компактный идентификатор записи в базе данных. Получить ссылку дёшево: она не тянет за собой содержимое объекта. Именно поэтому запросы и реквизиты ссылочного типа всегда возвращают ссылки — это быстро и экономно по памяти. Через ссылку можно читать реквизиты (платформа неявно выполнит запрос к базе), но нельзя их изменять.
Объект (типы вида СправочникОбъект, ДокументОбъект) — это полноценная копия данных в памяти. Его получают вызовом Объект = Ссылка.ПолучитьОбъект();. Теперь реквизиты можно менять, табличные части — заполнять, а после изменений нужно вызвать Объект.Записать();, иначе все правки останутся в памяти и пропадут.
Важное следствие: два разных вызова ПолучитьОбъект() для одной ссылки создают два независимых объекта в памяти. Если изменить и записать первый, второй об этом не узнает, и при его записи можно получить конфликт версий или перезаписать чужие изменения. В долгих процедурах объект получают один раз и переиспользуют.
Ссылка = Справочники.Номенклатура.НайтиПоКоду("000001");
Объект = Ссылка.ПолучитьОбъект();
Объект.Наименование = "Новое наименование";
Объект.Записать();Метод Значение(): преобразование данных
Отдельный смысл слова «значение» связан с методом Значение(), который встречается у нескольких типов платформы. Самый известный случай — ЗначениеВСтрокуВнутр и обратные механизмы, но чаще разработчик сталкивается с методом Значение() у объектов типа «ОписаниеТипов» — нет, корректнее сказать о типичном применении: у элементов формы, у параметров компоновки и у данных запроса.
Наиболее частый практический сценарий — работа с параметрами сеанса, настройками СКД и хранилищем значения. Реквизит типа «ХранилищеЗначения» не содержит данные напрямую: чтобы получить вложенное значение, вызывают Хранилище.Получить(). Аналогично, чтобы положить данные в хранилище, используют конструктор Новый ХранилищеЗначения(Значение). Путаница между «положить» и «получить» — классический источник ошибок «значение не является объектным».
Ещё один контекст — функция ЗначениеЗаполнено(Значение). Она проверяет, отличается ли значение от значения по умолчанию для своего типа: пустая строка, нулевое число, пустая дата, пустая ссылка считаются незаполненными. Это стандартный способ валидации перед записью или проведением.
Передача параметров: по значению и по ссылке
Понятие значения напрямую влияет на поведение процедур и функций. По умолчанию параметры передаются по ссылке: если внутри процедуры изменить параметр, изменится и переменная в месте вызова. Если в объявлении параметра указать ключевое слово Знач, параметр передаётся по значению — внутри процедуры работает копия, и исходная переменная не меняется.
Здесь есть тонкость, о которой забывают даже опытные разработчики: Знач защищает саму переменную, но не данные ссылочного типа внутри неё. Если передать таблицу значений с Знач, изменить её строки всё равно можно — копируется только ссылка на таблицу, а не её содержимое. Для полной независимости нужен явный Таблица.Скопировать().
На серверных вызовах с клиента действует дополнительное ограничение: не все типы сериализуются и могут пересекать границу клиент–сервер. Например, ДокументОбъект передать нельзя — только ссылку или примитивные структуры данных. Попытка вернуть объект из серверной функции завершится ошибкой преобразования.
Как проверить и изменить значение объекта на практике
Типовая задача: в обработке нужно обновить реквизит у найденного элемента справочника. Безопасная последовательность выглядит так: найти ссылку, проверить, что она найдена и не помечена на удаление, получить объект, изменить реквизиты, записать в транзакции, если изменений несколько и они связаны.
Для проверки того, что лежит в переменной, удобны функции ТипЗнч(Значение) и сравнение через Тип("СправочникСсылка.Номенклатура"). В отладчике значение объекта видно раскрытием переменной: платформа покажет реквизиты и табличные части. Для ссылки отладчик покажет представление и уникальный идентификатор.
Если объект изменяется в цикле по многим элементам, не записывайте его на каждой итерации без необходимости — но и не копите сотни объектов в памяти. Разумный компромисс: получить объект, изменить, записать, освободить. При массовой обработке полезно обернуть пачку операций в транзакцию с понятным размером порции.
- 1Найдите ссылку: НайтиПоКоду(), НайтиПоНаименованию() или запросом.
- 2Проверьте результат: Ссылка.Пустая() или ЗначениеЗаполнено(Ссылка).
- 3Получите объект: Объект = Ссылка.ПолучитьОбъект().
- 4Измените нужные реквизиты и табличные части.
- 5Вызовите Объект.Записать() и убедитесь, что исключений не возникло.
- 6Проверьте результат чтением реквизита из базы или через форму элемента.
Риски и ограничения при работе со значениями объектов
Главный риск — запись объекта, данные которого устарели. Пока ваш код держал объект в памяти, другой пользователь мог изменить тот же элемент. При записи платформа может выдать ошибку конфликта блокировок, а в некоторых сценариях изменения молча перезапишутся. Для критичных операций используйте управляемые блокировки или минимизируйте время между чтением и записью.
Второй риск — производительность. Чтение реквизитов через точку от ссылки в цикле порождает отдельный запрос к базе на каждую итерацию. Если нужно прочитать много данных, правильнее один запрос с выборкой, чем тысяча обращений через ссылки. Правило простое: ссылки — для идентификации, запросы — для чтения массивов данных, объекты — для изменения.
Третье ограничение касается обмена данными и подписок на события. При записи объекта срабатывают обработчики ПередЗаписью и ПриЗаписи, которые могут изменить данные или отменить запись. Если код ведёт себя «странно», проверьте подписки на события и обработчики в модуле объекта — значение, которое вы присвоили, могло быть переопределено логикой конфигурации.
Частые вопросы
Чем ссылка отличается от значения объекта?
Ссылка — это только идентификатор записи в базе, она позволяет читать реквизиты, но не менять их. Значение объекта — это сами данные в памяти, полученные через ПолучитьОбъект(); их можно изменять и затем записывать методом Записать().
Почему изменения объекта не сохраняются?
Чаще всего не вызван метод Записать() — объект существует только в памяти сеанса. Реже запись отменяется в обработчике ПередЗаписью (Отказ = Истина) или изменения вносились в другую копию объекта, полученную отдельным вызовом ПолучитьОбъект().
Что делает ключевое слово Знач в параметрах процедуры?
Оно передаёт параметр по значению: внутри процедуры работает копия переменной, и присваивание нового значения параметру не влияет на исходную переменную. Однако для ссылочных типов (таблица значений, массив внутри структуры) копируется только указатель — содержимое остаётся общим.
Как проверить, пустое ли значение?
Универсальный способ — функция ЗначениеЗаполнено(Значение): она корректно обрабатывает пустые строки, нули, пустые даты и пустые ссылки. Для ссылок также подходит Ссылка.Пустая(). Сравнение с Неопределено работает только для типов, допускающих это значение.
Можно ли передать объект документа с сервера на клиент?
Нет, типы вида ДокументОбъект не сериализуются и не пересекают границу клиент–сервер. Передавайте ссылку, а на клиенте при необходимости открывайте форму документа, либо передавайте нужные данные в виде структуры с простыми типами.
Зачем нужен ХранилищеЗначения и как из него достать данные?
ХранилищеЗначения позволяет сохранить в реквизите базы произвольные данные: картинку, таблицу значений, файл. Чтобы получить вложенное значение, вызовите Реквизит.Получить(); чтобы положить — присвойте реквизиту Новый ХранилищеЗначения(Данные).
Что важно запомнить
Значение объекта в 1С — это данные экземпляра в памяти, а ссылка — лишь его адрес в базе. Читайте через ссылки и запросы, изменяйте через ПолучитьОбъект() с обязательным Записать(), помните про разницу передачи параметров по значению и по ссылке и проверяйте заполненность через ЗначениеЗаполнено().