Оператор spread и rest-параметры

Операторы spread и rest являются частью современного синтаксиса JavaScript и активно используются для работы с массивами, объектами и параметрами функций. В экосистеме SWC (Speedy Web Compiler) эти конструкции проходят стадию трансформации, обеспечивая совместимость с более старыми средами выполнения и сохраняя при этом высокую скорость компиляции.

Семантика spread-оператора

Spread-оператор () используется для «разворачивания» итерируемых структур или объектов в местах, где ожидаются отдельные элементы.

Массивы

const a = [1, 2];
const b = [3, 4];

const result = [...a, ...b];

В этом случае массивы a и b разворачиваются в последовательность элементов, формируя новый массив.

Эквивалентная логика без spread:

const result = a.concat(b);

Spread в массивах также применяется для копирования:

const original = [1, 2, 3];
const copy = [...original];

Spread в объектах

В объектах spread позволяет копировать и объединять свойства:

const base = { a: 1, b: 2 };
const extended = { ...base, c: 3 };

Поверхностное копирование сохраняет только первый уровень вложенности.

Особенность поведения при конфликте ключей:

const a = { x: 1 };
const b = { x: 2 };

const merged = { ...a, ...b };

Значение из b перезапишет значение из a.


Rest-параметры в функциях

Rest-параметры позволяют собирать неопределённое количество аргументов в массив.

function sum(...args) {
  return args.reduce((acc, n) => acc + n, 0);
}

Внутри функции args становится полноценным массивом.

Пример вызова:

sum(1, 2, 3, 4);

Rest-параметр всегда находится в конце списка параметров:

function fn(a, b, ...rest) {}

Деструктуризация с rest

Rest также применяется при деструктуризации массивов и объектов.

Массивы

const [first, ...rest] = [1, 2, 3, 4];

first получает первый элемент, rest — оставшиеся.

Объекты

const { a, ...others } = { a: 1, b: 2, c: 3 };

Переменная others содержит объект без свойства a.


Обработка spread и rest в SWC

SWC — высокопроизводительный компилятор JavaScript, написанный на Rust. Он выполняет трансформацию современного синтаксиса в совместимый ES5/ES2015 код.

Spread и rest относятся к синтаксическим конструкциям, которые часто требуют преобразования в более старые выражения.

Трансформация rest-параметров

Функции с rest-параметрами преобразуются в код, где используется объект arguments.

Исходный код:

function fn(...args) {
  return args;
}

После трансформации SWC:

function fn() {
  var args = Array.prototype.slice.call(arguments);
  return args;
}

При наличии фиксированных параметров:

function fn(a, b, ...args) {
  return args;
}

Трансформация:

function fn(a, b) {
  var args = Array.prototype.slice.call(arguments, 2);
  return args;
}

Здесь индекс 2 указывает на начало rest-части.


Трансформация spread в массивах

Spread в массивах часто преобразуется в concat или вспомогательные функции.

const arr = [...a, ...b];

Возможный результат компиляции:

var arr = [].concat(a, b);

При более сложных выражениях SWC может использовать временные переменные для сохранения порядка вычислений:

const arr = [...getA(), 2, ...getB()];

Может быть преобразовано в:

var _a = getA(), _b = getB();
var arr = [].concat(_a, [2], _b);

Spread в объектах и его преобразование

Object spread не имеет прямого аналога в ES5, поэтому SWC использует вспомогательные функции, аналогичные Object.assign.

const obj = { ...a, b: 2 };

Трансформация:

var obj = Object.assign({}, a, { b: 2 });

Если включена более строгая совместимость, SWC может генерировать хелпер-функции:

function _extends() {
  return (_extends = Object.assign || function (target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i];
      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          target[key] = source[key];
        }
      }
    }
    return target;
  }).apply(this, arguments);
}

var obj = _extends({}, a, { b: 2 });

Деструктуризация с rest в SWC

При компиляции деструктуризации SWC генерирует код, исключающий перечисленные свойства из исходного объекта.

const { a, ...rest } = obj;

Трансформация:

var a = obj.a;
var rest = {};

for (var key in obj) {
  if (key !== "a" && Object.prototype.hasOwnProperty.call(obj, key)) {
    rest[key] = obj[key];
  }
}

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


Порядок вычисления и побочные эффекты

Spread-операторы сохраняют порядок вычисления выражений. SWC учитывает это при генерации промежуточных переменных.

const result = [...fn1(), ...fn2()];

Компиляция:

var _fn = fn1();
var _fn2 = fn2();
var result = [].concat(_fn, _fn2);

Такой подход предотвращает повторные вызовы функций и сохраняет корректный порядок выполнения.


Особенности оптимизации SWC

SWC применяет несколько стратегий для повышения эффективности:

  • сокращение количества временных переменных;
  • выбор concat вместо ручных циклов для массивов;
  • использование встроенного Object.assign, если доступен;
  • генерация минимального количества вспомогательных функций;
  • сохранение исходного порядка операций при трансформации.

Ограничения трансформации

Некоторые случаи spread и rest требуют более сложной обработки:

  • spread над неитерируемыми значениями вызывает ошибки ещё до трансформации;
  • глубокое копирование объектов не поддерживается;
  • символы и non-enumerable свойства требуют осторожной обработки;
  • динамические ключи при object rest могут усложнять генерацию кода.

SWC стремится сохранять поведение спецификации ECMAScript, но при этом ориентируется на баланс между точностью и скоростью компиляции.


Совместимость с target-окружениями

При выборе целевой версии JavaScript SWC адаптирует трансформации:

  • ES2018+ — минимальная трансформация, spread может оставаться как есть;
  • ES2015 — частичная трансформация объектов и массивов;
  • ES5 — полная транспиляция всех spread/rest конструкций.

Выбор target влияет на глубину генерируемого кода и количество вспомогательных функций.


Взаимодействие с другими трансформациями

Spread и rest часто комбинируются с другими синтаксическими преобразованиями:

  • деструктуризацией;
  • стрелочными функциями;
  • классами;
  • async/await.

В таких случаях SWC строит цепочку преобразований, где spread/rest может быть обработан как на раннем, так и на позднем этапе, в зависимости от конфигурации плагинов и пресетов.