Как объявлять, вызывать и отлаживать функции во встроенном языке 1С:Предприятия 8.3
Содержание
Функция во встроенном языке 1С объявляется так: Функция Имя(Параметры), внутри — код и оператор Возврат Значение;, в конце — КонецФункции. От процедуры она отличается только тем, что возвращает результат, поэтому её можно вызвать прямо в выражении: Сумма = РассчитатьСкидку(Цена, 10);. Чтобы использовать функцию из другого модуля, добавьте после списка параметров слово Экспорт.
Всё, что ниже, относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: правила одинаковы в Бухгалтерии, ЗУП, УТ и в собственной разработке. Разберём синтаксис, параметры, возврат значений, встроенные функции платформы, рекурсию, обработку ошибок и то, что тормозит вызовы в клиент-серверном режиме.
Как объявить функцию в 1С и где её видно
Минимальная функция выглядит так:
Функция РассчитатьСкидку(Цена, Процент)
Возврат Цена * Процент / 100;
КонецФункции
Из чего состоит объявление:
- 🔹 Имя — латиница или кириллица, без пробелов, не начинается с цифры. По соглашениям 1С имена пишут слитно с заглавной буквы каждого слова:
ПолучитьОстатокТовара. - 🔹 Параметры — через запятую в скобках. Скобки ставятся, даже если параметров нет:
Функция ТекущийПользователь(). - 🔹 Экспорт — делает функцию доступной снаружи модуля.
- 🔹 Директива компиляции — строка над объявлением в модулях форм и команд:
&НаКлиенте,&НаСервере,&НаСервереБезКонтекста,&НаКлиентеНаСервереБезКонтекста.
Область видимости функции
Где функцию можно вызвать, зависит от модуля и от слова Экспорт.
| Где объявлена | Без Экспорт | С Экспорт |
|---|---|---|
| Модуль формы | только в этой форме | не нужен: снаружи формы её всё равно не вызвать напрямую |
| Модуль объекта (документа, справочника) | только в модуле объекта | через объект: ДокОбъект.Пересчитать() |
| Модуль менеджера | только в модуле менеджера | через менеджер: Документы.РеализацияТоваров.ДанныеДляПечати(...) |
| Общий модуль | только внутри общего модуля | из любого места: РаботаСЦенами.ЦенаНоменклатуры(...) |
У общего модуля в палитре свойств стоят флажки контекста: Клиент (управляемое приложение), Сервер, Вызов сервера, Внешнее соединение, Глобальный, Привилегированный. Если функция серверная, а вызвать её нужно с клиента, у модуля должен стоять флажок Вызов сервера. Без него клиентский код функцию просто не увидит.
Переменные внутри функции
Локальная переменная появляется при первом присваивании. Явно её объявляют оператором Перем в начале тела. Локальные переменные живут только на время вызова.
Переменные модуля (Перем в начале модуля) видны во всех функциях этого модуля. В модуле формы и общем модуле злоупотреблять ими не стоит: состояние модуля сложнее отследить, а серверный модуль формы между вызовами его не хранит.
Параметры: по ссылке, по значению и необязательные
По умолчанию параметр передаётся по ссылке. Если функция присвоит параметру новое значение, оно изменится и в вызывающем коде.
Процедура Увеличить(Число)
Число = Число + 1;
КонецПроцедуры
А = 5;
Увеличить(А); // теперь А = 6
Слово Знач перед параметром включает передачу по значению: функция работает с копией, а исходная переменная не меняется.
Функция Удвоить(Знач Число)
Число = Число * 2;
Возврат Число;
КонецФункции
Знач защищает переменную, но не содержимое коллекции. Если передать таблицу значений с Знач и добавить в неё строку, строка появится и у вызывающего кода: копируется ссылка на объект, а не сама таблица. Нужна независимая копия — сделайте Таблица.Скопировать().
Значения по умолчанию
Необязательный параметр получает значение по умолчанию прямо в объявлении:
Функция Округлить(Сумма, Разрядов = 2)
Возврат Окр(Сумма, Разрядов);
КонецФункции
Округлить(10.456); // 10.46
Округлить(10.456, 0); // 10
Необязательные параметры ставят в конец списка. Пропустить параметр в середине можно запятой: СоздатьЗапись(Ссылка, , Истина). Такой вызов плохо читается, поэтому при 4-5 необязательных параметрах лучше передать одну Структура с настройками.
Как функция 1С возвращает значение
Оператор Возврат сразу завершает функцию и отдаёт результат. Код после него в этой ветке не выполняется. Ранний выход упрощает проверки:
Функция ЦенаСоСкидкой(Цена, Процент)
Если Цена <= 0 Тогда
Возврат 0;
КонецЕсли;
Если Процент > 100 Тогда
Процент = 100;
КонецЕсли;
Возврат Цена - Цена * Процент / 100;
КонецФункции
Правила возврата:
- Функция может вернуть значение любого типа: число, строку, ссылку, массив, структуру, таблицу значений.
- Если выполнение дошло до
КонецФункциибезВозврат, функция вернётНеопределено. - Функцию можно вызвать как процедуру — результат просто отбросится:
ЦенаСоСкидкой(100, 5);. - Процедуру как функцию вызвать нельзя:
Х = Увеличить(А);не пройдёт синтаксический контроль. - В процедуре
Возвратпишут без значения — он просто прерывает выполнение.
Как вернуть несколько значений
Одним Возврат отдают одно значение. Если нужно несколько, есть два способа.
Структура — понятный и рекомендуемый:
Функция ИтогиПоДокументу(Документ)
Результат = Новый Структура("Сумма, СуммаНДС, Количество", 0, 0, 0);
Для Каждого Строка Из Документ.Товары Цикл
Результат.Сумма = Результат.Сумма + Строка.Сумма;
Результат.СуммаНДС = Результат.СуммаНДС + Строка.СуммаНДС;
Результат.Количество = Результат.Количество + Строка.Количество;
КонецЦикла;
Возврат Результат;
КонецФункции
Итоги = ИтогиПоДокументу(ДокОбъект);
Сообщить(Итоги.СуммаНДС);
Параметры по ссылке — функция возвращает признак успеха, а данные кладёт в параметр: Если ПрочитатьФайл(Путь, Текст) Тогда. Работает, но такой код хуже читается.
Встроенные функции 1С для работы с данными
Встроенные функции платформы не нужно объявлять — они есть в глобальном контексте. Полный список открывается в Конфигураторе через синтакс-помощник: Справка → Синтакс-помощник, раздел «Глобальный контекст». Ниже — те, что встречаются в коде каждый день.
Строки
Строка = " ООО Ромашка; ИНН 7701234567 ";
Чистая = СокрЛП(Строка); // убирает пробелы по краям
Длина = СтрДлина(Чистая);
Части = СтрРазделить(Чистая, ";"); // массив из 2 строк
Поз = СтрНайти(Чистая, "ИНН"); // позиция подстроки, 0 если нет
ИНН = СокрЛП(Сред(Чистая, Поз + 3)); // "7701234567"
Текст = СтрШаблон("Контрагент %1, ИНН %2", СокрЛП(Части[0]), ИНН);
СтрНайти, СтрРазделить, СтрСоединить и СтрШаблон появились в 8.3.6. В старом коде вместо них встречаются Найти и разбор строки циклом.
Числа и даты
Окр(1234.567, 2); // 1234.57
Цел(7.9); // 7
Макс(3, 8, 5); // 8
НачалоМесяца(ТекущаяДатаСеанса());
ДобавитьМесяц('20260131', 1); // 28.02.2026 — последний день февраля
Для серверной логики берите ТекущаяДатаСеанса(), а не ТекущаяДата(): первая учитывает часовой пояс сеанса, вторая возвращает время компьютера, где выполняется код.
Типы и преобразования
- 🔸
ТипЗнч(Значение) = Тип("Число")— проверка типа. - 🔸
ЗначениеЗаполнено(Значение)— пустая ли ссылка, строка, дата, ноль. - 🔸
Число("12.5"),Строка(42),Дата("20260101"),Булево(1)— преобразования.Число()на строке «12,5 руб.» вызовет исключение. - 🔸
Формат(1234567.8, "ЧДЦ=2; ЧГ=0")— число без пробелов-разделителей:1234567.80.
Склеивая число со строкой, всегда используйте Формат или СтрШаблон. Иначе "Код " + 1500 даст Код 1 500 с неразрывным пробелом, и такой код не найдётся в базе.
Собственные функции и рекурсия в 1С
Свою функцию выносят тогда, когда один и тот же кусок кода нужен в 2-3 местах или когда процедура перевалила за экран. Хорошая функция делает одно дело и называется глаголом: ПолучитьКурсВалюты, ПроверитьЗаполнениеИНН.
Где хранить:
- 📁 логика одного документа — в модуле объекта или менеджера;
- 📁 общая логика для многих объектов — в общем модуле с понятным именем;
- 📁 код для внешних обработок и отчётов — в модуле самой обработки.
Рекурсия: функция вызывает сама себя
Рекурсия удобна для иерархий: дерево значений, группы справочника, вложенные структуры. Пример — подсчёт всех строк дерева значений на любом уровне вложенности:
Функция КоличествоСтрокДерева(СтрокиДерева)
Всего = 0;
Для Каждого Строка Из СтрокиДерева Цикл
Всего = Всего + 1 + КоличествоСтрокДерева(Строка.Строки);
КонецЦикла;
Возврат Всего;
КонецФункции
Количество = КоличествоСтрокДерева(Дерево.Строки);
Функция обходит строки текущего уровня, а для каждой строки вызывает себя на её подчинённых. Когда у строки нет потомков, цикл не выполняется, и функция возвращает 0 — это и есть условие выхода.
Рекурсия без условия выхода роняет сеанс. Глубина стека вызовов ограничена, при её превышении платформа прерывает выполнение с ошибкой. Если иерархия в данных может быть зациклена (элемент ссылается на себя как на родителя), передавайте в рекурсию счётчик уровня и останавливайтесь, например, на 100.
Для иерархических справочников рекурсия часто не нужна вовсе: запрос с условием В ИЕРАРХИИ получает все вложенные элементы одним обращением к базе.
Сводная таблица функций для разработчика
| Задача | Функция или конструкция | Пример |
|---|---|---|
| Объявить функцию | Функция … КонецФункции | Функция Итог(А, Б) |
| Открыть для других модулей | Экспорт | Функция Итог(А, Б) Экспорт |
| Защитить параметр от изменения | Знач | Функция Ф(Знач Сумма) |
| Необязательный параметр | = значение | Функция Ф(Сумма, НДС = 20) |
| Вернуть результат | Возврат | Возврат Сумма * 1.2; |
| Убрать пробелы | СокрЛП | СокрЛП(" ИНН ") |
| Разбить строку | СтрРазделить | СтрРазделить(Стр, ",") |
| Подставить значения в текст | СтрШаблон | СтрШаблон("%1 руб.", Сумма) |
| Округлить | Окр | Окр(Сумма, 2) |
| Сдвинуть дату на месяцы | ДобавитьМесяц | ДобавитьМесяц(Дата, -1) |
| Проверить тип | ТипЗнч, Тип | ТипЗнч(Х) = Тип("Строка") |
| Проверить пустоту | ЗначениеЗаполнено | ЗначениеЗаполнено(Контрагент) |
| Вывести число как текст | Формат | Формат(Код, "ЧГ=0") |
| Перехватить ошибку | Попытка … Исключение | см. ниже |
| Сгенерировать ошибку | ВызватьИсключение | ВызватьИсключение "Не задан склад"; |
| Текст ошибки | ОписаниеОшибки() | внутри блока Исключение |
Ошибки внутри функций: Попытка, Исключение и отладка
Если в функции возникает ошибка выполнения (деление на ноль, обращение к несуществующему полю, неверное преобразование), выполнение прерывается и ошибка поднимается к вызывающему коду. Перехватывают её конструкцией Попытка … Исключение … КонецПопытки:
Функция ЧислоИзСтроки(Текст)
Попытка
Возврат Число(Текст);
Исключение
ЗаписьЖурналаРегистрации("Преобразование числа",
УровеньЖурналаРегистрации.Предупреждение, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат 0;
КонецПопытки;
КонецФункции
Что важно при перехвате:
- ❗ Не глушите ошибки молча. Пустой блок
Исключениепрячет проблему, и потом неделями ищут, почему сумма ноль. Минимум — запись в журнал регистрации. - ❗ Транзакцию начинают до
Попытка, а в блокеИсключениеотменяют и пробрасывают ошибку дальше:
НачатьТранзакцию();
Попытка
ЗаписатьДвижения(Документ);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
- ❗
ВызватьИсключениебез текста внутри блокаИсключениепробрасывает исходную ошибку со всеми подробностями. С текстом — создаёт новую ошибку с вашим сообщением.
Свою ошибку для пользователя генерируют так: ВызватьИсключение "Не указан склад в строке " + Формат(НомерСтроки, "ЧГ=0");.
Отладка функции в Конфигураторе
- Поставьте точку останова на строке внутри функции клавишей
F9. - Запустите отладку:
Отладка → Начать отладку → 1С:Предприятиеили клавишейF5. - Выполните в пользовательском режиме действие, которое вызывает функцию.
- Когда выполнение остановится, ходите по шагам:
F11— с заходом в вызываемую функцию,F10— без захода,Shift+F11— выйти из текущей функции. - Значение любого выражения смотрите через
Shift+F9или добавьте переменную в окно «Табло». - Окно «Стек вызовов» покажет, через какую цепочку функций вы сюда попали — так находят, кто передал неверный параметр.
Если точка останова в серверной функции не срабатывает в клиент-серверной базе, проверьте, что на сервере 1С включена отладка. Без этого остановятся только клиентские функции.
Как ускорить вызовы функций в клиент-серверном режиме
Сама по себе функция работает быстро. Время уходит на две вещи: вызовы сервера с клиента и обращения к базе.
Сократите число вызовов сервера
Каждый вызов функции с директивой &НаСервере из клиентского кода формы — отдельный обмен с сервером. Вместе с ним на сервер и обратно передаются данные формы. Пять серверных вызовов в обработчике кнопки — пять обменов по сети.
Что помогает:
- ⚡ Собрать работу в одну серверную функцию и вызвать её один раз.
- ⚡ Использовать
&НаСервереБезКонтекста, если функции не нужны реквизиты формы: данные формы тогда не передаются, а всё нужное идёт через параметры. - ⚡ Объявлять параметры серверных функций, вызываемых с клиента, через
Знач. Параметры безЗначпосле вызова возвращаются на клиент, а это лишний трафик.
Не обращайтесь к базе в цикле
Типичный тормоз — запрос или чтение реквизита через точку внутри цикла:
// Медленно: на каждой строке отдельное чтение объекта
Для Каждого Строка Из Товары Цикл
Если Строка.Номенклатура.Услуга Тогда
...
КонецЕсли;
КонецЦикла;
Обращение Ссылка.Реквизит читает объект из базы. На 1000 строк — 1000 обращений. Правильнее получить нужные реквизиты всех товаров одним запросом до цикла, а в цикле искать в полученной таблице. В типовых конфигурациях на БСП для этого есть функции общего модуля ОбщегоНазначения, например ЗначенияРеквизитовОбъектов.
Кэшируйте то, что не меняется
У общего модуля есть свойство Повторное использование возвращаемых значений: «На время вызова» или «На время сеанса». Функция такого модуля при одинаковых параметрах вычисляется один раз, дальше результат берётся из кэша. Подходит для настроек, констант, функциональных опций. Не подходит для остатков и цен: кэш вернёт устаревшие данные.
Найти узкое место помогает замер производительности: Отладка → Замер производительности в Конфигураторе во время отладки показывает, сколько времени и сколько раз выполнялась каждая строка.