JavaScript

Область кода Выражения должна содержать код JavaScript.

Код Выражения является телом функции, которая должна возвращать значение. Для возврата этого значения используется return. Однако, если код представлен единственным выражением JavaScript, то применять return не обязательно.

Примечание. Имена узлов/переменных/выражений чувствительны к регистру.

Дерево данных доступно в коде JavaScript как объект глобальной области видимости с именем ${Имя_корневого_узла}. Объект дерева данных объединяет исходное дерево и узлы, формируемые по Выражениям. В Выражении возможно использование ссылок на другие выражения.

При ссылках на узлы дерева имеется возможность задавать абсолютные или относительные пути. Абсолютные ссылки на узлы дерева представляют из себя строку, в которой через точку перечислены родители узла в их иерархии начиная с корневого узла. Пример: $Root.Orders.Order[0].Address. Относительные ссылки могут задаваться с помощью встроенной функции Parent(), возвращающей родителский узел для узла текущего Выражения. Пример: Parent().Order[0].Address.

Узлы дерева, не являющиеся значениями простых типов, имеют свойство $Parent, позволяющее обращаться к другим узлам из кода выражения относительно. У элементов массива свойство $Parent возвращает объект типа Array.

У узлов-контейнеров, являющихся элементами массива, есть свойство $Index, возвращающее индекс текущего элемента в массиве.

Следующий пример демонстрирует вычисление суммы значений узла в корне дерева и переменной:

// Вычисление суммы значений узла дерева и переменной
let result;
result = $Root.Value1 + this.Var.MyVar;

return result;

В теле скрипта можно использовать ссылки на другие узлы или переменные, в том числе новые, созданные в списке выражений. Через промежуточное выражение с типом Переменный можно передать массив. Ко входным Переменным можно обращаться через объект this.Var..

В данном примере для вычисления переменной result используются ссылки на узел с именем $Root.Value1 и входную переменную MyVar.

Для вывода результата в вычисляемое поле калькулятора используется команда return, которая возвращает значение переменной result, содержащей вычисленную сумму узлов дерева.

Компактный вариант кода вычисления суммы узлов дерева:

// Вычисление суммы значений узла и переменной
$Root.Value1 + this.Var.MyVar;

Пример создания и применения функции для вычисления сложного процента:

/* 
Функция вычисления сложного процента
Z = I * (1 + R / 100%) (в степени T), где 
Z — будущая сумма на счету;
I — начальная сумма вложений (InvestmentAmount);
R — процентная ставка в % (Rate);
T — срок вклада в годах (TimeSpan).
*/
function CompoundInterest(I, R, T) {
  // Z - будущая сумма на счету;
  let Z = I * Math.pow((1 + R / 100), T);
  // накопленные проценты = Z - I
  return Z - I;
}
// Вывод результата функции в качестве значения создаваемого в выражении узла
return CompoundInterest($Root.InvestmentAmount, $Root.Rate, $Root.TimeSpan);

В данном скрипте определена функция CompoundInterest(I, R, T), принимающая в качестве аргументов параметры расчета. Для вывода результата скрипта в вычисляемое поле калькулятора используется команда return CompoundInterest($Root.InvestmentAmount, $Root.Rate, $Root.TimeSpan), где CompoundInterest — объявленная функция, принимающая параметры из узлов дерева.

В коде JavaScript можно использовать встроенные функции Калькулятора:

function FinancialFormat(x) {
 let s;
 // s = x.concat(' руб.');      - используется метод JavaScript
 s = Concat(x, ' руб.');    //  - используется функция Калькулятора

return s;
}

return FinancialFormat($Root.SummaString);

Наименования встроенных функций Калькулятора и JavaScript не пересекаются. Функции Калькулятора всегда начинаются с большой буквы, однако, их можно переопределить в коде JS. Явного импорта функций Калькулятора (как это делается в компоненте JavaScript) делать не нужно.

Примечание: в отличии от компонента JavaScript в Калькуляторе не поддерживается объект Promise.

Импорт внешних модулей

Как и в компоненте JavaScript поддерживаются внешние модули, но в Калькуляторе (дерево) возможно использование только модульной системы CommonJS. Модульная система ES6 (ECMAScript 6) не поддерживается. С примерами и документацией использования модулей CommonJS можно ознакомиться в статье JavaScript: Импорт внешних модулей.

Особенности применения внешних модулей

Для импорта модуля CommonJS применяется функция require. Пример:

const foo = require("foo/foo.js");

Выполнение модуля происходит при первом вызове require. Последующие вызовы require забирают выполненный модуль из кэша. Кэш функции require доступен через объект require.cache.

Важно: использование кэша для передачи значений между выражениями может привести к непредсказуемым результатам вычислений ввиду использования пула интерпретаторов.

Если при использовании модуля меняется его внутреннее состояние, и это влияет на будущий результат, то может потребоваться удалить его из кэша после использования в выражении с помощью объекта require.cache:

let path = require.resolve("foo/foo.js");
delete require.cache[path];  // Очищается кэш модуля "foo/foo.js"

Важно: следует учитывать, что загрузка и выполнение модуля является затратной операцией, поэтому удаление модуля из кэша может серьёзно отразиться на производительности.

require можно использовать для импорта файла json:

// загрузить json из файла в объект
let jsonAsObj = require('/path/to/file.json')

Панель быстрого доступа

На панели расположена кнопка вызова окна Предпросмотр Предпросмотра и кнопки, по нажатию на которые в область кода выражения вставляется заготовка либо шаблон.

Предпросмотр Предпросмотр — позволяет оценить корректность расчетов, отображая результирующее дерево. Горячая клавиша вызова — F3.

Логические операции:

  • && — Логическое "И";
  • || — Логическое "ИЛИ";
  • ! — Логическое "НЕ".

Операторы сравнения:

  • = — Равно;
  • != — Не равно;
  • < — Меньше;
  • > — Больше;
  • <= — Меньше или равно;
  • >= — Больше или равно.

Шаблоны:

  • Вещественное число — для ввода вещественного числа, будет вставлено 0.0.
  • Строка — для ввода строки, будет вставлено "".
  • Дата — для ввода даты, будет вставлена конструкция создания объекта, содержащего текущую дату. Пример: new Date(2020, 1, 5).
  • Время — для ввода даты/времени, будет вставлена конструкция создания объекта, содержащего текущие дату/время. Пример: new Date(2020, 1, 5, 13, 12, 50, 100).

Логические значения:

  • false — Ложь;
  • true — Истина.

Примеры

Имеется входное дерево данных:

Структура дерева
Рисунок 1. Структура дерева
Данные дерева
Рисунок 2. Данные дерева

Пример 1

В узле Root.Orders создадим выражение OrdersCount, подсчитывающее общее колличество элементов в массиве Root.Orders.Order. Код JavaScript нового выражения будет следующим:

$Root.Orders.Order.length

Узел дерева Order в контексте JavaScript является объектом типа Array и будет иметь свойство length, которое используется для вывода длинны массива.

Абсолютной ссылкой на новый узел будет строка $Root.Orders.OrdersCount. Относительно $Root.Orders.OrdersCount функция Parent() вернет узел Orders, в котором содержится узел Order. Поэтому для вычисления выражения так же будет работать код с относительной ссылкой на узел Order:

Parent().Order.length

Пример 2

В узле Root.Orders создадим выражение LastShipmentDate, подсчитывающее максимальную дату ShippedDate в массиве Root.Orders.Order. Код JavaScript нового выражения будет следующим:

let orders = Parent().Order;
const c = orders.length;
if (!c) return undefined;
let lastDate = orders[0].ShipInfo.ShippedDate;
for (let i = 1; i < c; i++) {
    let shippedDate = orders[i].ShipInfo.ShippedDate;
    if (shippedDate > lastDate)
        lastDate = shippedDate;
}
return lastDate;

Здесь переменной orders присваивается массив Order. Для перебора в цикле элементов массива используется конструкция orders[i], где i — итерируемый в цикле индекс элемента массива.

Пример 3

Заменим строковые значения узлов $Root.Orders.Order[].ShipInfo.Freight на вещественные. Эти узлы находятся в элементах массива Order, поэтому для обращения к элементам используем функцию ItemIndex(), возвращающую индекс текущего элемента в массиве:

Number($Root.Orders.Order[ItemIndex()].ShipInfo.Freight)

Для возвращения индекса элемента в массиве так же можно использовать свойство $Index:

Number($Root.Orders.Order[Parent().$Parent.$Index].ShipInfo.Freight)

Здесь для обращения к элементам массива Order используется относительная ссылка Parent().$Parent. Функция Parent() возвращает родителя узла Freight, которым является узел ShipInfo, а свойство $Parent узла ShipInfo возвращает элемент массива Order, в котором содержится узел Freight. Свойство $Index элемента массива возвращает индекс этого элемента. Таким образом, конструкция Parent().$Parent.$Index возвращает индекс элемента массива Order, в котором содержится текущий узел Freight. В процессе расчета Калькулятор (дерево) перебирает и пересчитывает все узлы дерева, для которых определены Выражения.

Для замены исходных значений узлов на новые, вычисленные в Выражении, необходимо включить опцию  Заменять узел.