Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. Исчерпывающий гайд по деструктуризации и оператору ... (spread/rest - три точки, многоточие) в JavaScript

Исчерпывающий гайд по деструктуризации и оператору ... (spread/rest - три точки, многоточие) в JavaScript

Запланировано Прикреплена Закрыта Перенесена JavaScript
3 Сообщения 3 Постеры 119 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • AladdinA Не в сети
    AladdinA Не в сети
    Aladdin
    js
    написал в отредактировано Aladdin
    #1

    Главное: деструктуризация упрощает извлечение данных из объектов и массивов, а троеточие используется в двух разных ролях — spread «раскрывает» коллекции, а rest «собирает остатки». Освойте базовые шаблоны ниже — и получите удобную шпаргалку для повседневной разработки и собеседований.^1^3^5^7^9

    Оглавление

    • Что такое деструктуризация
    • Деструктуризация массивов
    • Деструктуризация объектов
    • Глубокая (вложенная) деструктуризация
    • Значения по умолчанию и вычисляемые значения
    • Переименование переменных при деструктуризации
    • Игнорирование элементов и «сбор остатка» с rest
    • Деструктуризация в параметрах функций
    • Типичные практики и частые ошибки
    • Оператор …: spread vs rest
    • Практические кейсы со spread
    • Полезные паттерны для React/Node.js/TS
    • Шпаргалка (Cheatsheet)

    Что такое деструктуризация

    Деструктурирующее присваивание — это синтаксис, позволяющий «распаковывать» элементы массива или свойства объекта в переменные напрямую, делая код короче и нагляднее.^2^7
    Пример: const [a, b] = arr; или const {x, y} = obj; извлекают значения в переменные с одной строки вместо нескольких обращений по индексу/ключу.^4^2


    Деструктуризация массивов

    Простая распаковка:

    const arr = [10, 20, 30];
    const [first, second, third] = arr;
    

    Пропуск элементов:

    const [x, , z] = [1, 2, 3]; // x=1, z=3
    

    Обмен значений без временной переменной:^2

    let a = 1, b = 3;
    [a, b] = [b, a]; // a=3, b=1
    

    Значения по умолчанию:^7

    const [a = 1, b = 2, c = 3] = [^10]; // a=10, b=2, c=3
    

    Остаток массива с rest:

    const [head, ...tail] = [1, 2, 3, 4]; // head=1, tail=[2,3,4]
    

    Результаты split()/match():

    const [firstName, lastName] = 'Ada Lovelace'.split(' '); // firstName='Ada'
    

    Возврат нескольких значений функцией:^2

    function minmax(nums) { return [Math.min(...nums), Math.max(...nums)]; }
    const [min, max] = minmax([5,1,9]); // min=1, max=9
    

    Деструктуризация объектов

    Базовая распаковка:

    const person = { name: 'Alice', age: 30 };
    const { name, age } = person;
    

    Значения по умолчанию:

    const { city = 'Unknown' } = {};
    

    Переименование переменных:

    const user = { id: 42, isAdmin: true };
    const { id: userId, isAdmin: admin } = user; // userId=42, admin=true
    

    Сбор «остатка» полей (object rest):^3

    const obj = { a: 1, b: 2, c: 3 };
    const { a, ...rest } = obj; // a=1, rest={ b:2, c:3 }
    

    Деструктуризация с вычисляемым именем ключа:

    const key = 'score';
    const stats = { score: 99, level: 3 };
    const { [key]: currentScore } = stats; // currentScore=99
    

    Глубокая (вложенная) деструктуризация

    Извлечение из вложенных объектов:^11

    const user = {
      name: 'John',
      contact: { email: 'john@ex.com', phones: { mobile: '123', work: '456' } },
      roles: ['user', 'editor']
    };
    
    const {
      name,
      contact: { email, phones: { mobile } },
      roles: [primaryRole]
    } = user;
    // name='John', email='john@ex.com', mobile='123', primaryRole='user'
    

    Смешанная с массивами:

    const data = {
      items: [{ id: 1, tags: ['a','b'] }, { id: 2, tags: ['c'] }]
    };
    const { items: [{ id: firstId, tags: [firstTag] }] } = data;
    // firstId=1, firstTag='a'
    

    Осторожно с отсутствующими ветками — используйте значения по умолчанию для безопасности:

    const cfg = {};
    const { server: { host = '127.0.0.1' } = {} } = cfg;
    

    Значения по умолчанию и вычисляемые значения

    Значения по умолчанию вычисляются лениво — выражение вызывается только если поле/элемент отсутствует:^7

    function computeDefault() { console.log('called'); return 100; }
    
    const [x = computeDefault()] = []; // вызов произойдёт
    const [y = computeDefault()] = [^5]; // не вызовется
    

    Переименование переменных при деструктуризации

    Объекты:

    const { name: fullName, age: years } = { name: 'M', age: 20 };
    

    Массивы переименовывают именами слева:

    const [width: w, height: h] = ??? // так нельзя
    // Для массивов просто используйте нужные имена:
    const [w, h] = [800, 600];
    

    Игнорирование элементов и «сбор остатка» с rest

    Игнорирование:

    const [ , second ] = [1,2,3]; // second=2
    

    Сбор остатка:

    const [first, ...others] = [1,2,3,4]; // others=[2,3,4]
    const { a, ...restObj } = { a:1, b:2, c:3 }; // restObj={ b:2, c:3 }
    

    Rest всегда стоит последним и допускается только один rest.^9


    Деструктуризация в параметрах функций

    Массивы в параметрах:^12

    function parseDate([year, month, day]) {
      return new Date(year, month - 1, day);
    }
    parseDate([2025, 12, 31]);
    

    Объекты в параметрах:

    function createUser({ name, email, role = 'user' }) {
      return { name, email, role };
    }
    

    Глубокая деструктуризация прямо в сигнатуре:

    function handle({ meta: { id }, payload: { items: [first] = [] } = {} }) {
      return { id, first };
    }
    

    С rest-параметрами:^13

    function sum(label, ...nums) {
      console.log(label, nums.reduce((a,b)=>a+b,0));
    }
    sum('total', 1,2,3); // nums=[1,2,3]
    

    Типичные практики и частые ошибки

    • Обмен значений без временной переменной с массивной деструктуризацией.^2
    • Выборка нужных полей из ответа API, игнорируя всё остальное.
    • Осторожно: «плоская» деструктуризация вложенных полей может кидать ошибку, если промежуточный объект undefined. Используйте значения по умолчанию для узлов: const { a: { b } = {} } = obj.
    • Нельзя использовать объектную деструктуризацию слева без объявления без скобок:
    // ({a} = someObj); // обернуть в скобки при присваивании существующим переменным
    
    • Rest-параметр должен быть последним и единственным rest.^9
    • Не путать spread и rest: одинаковый синтаксис …, но разные контексты и смысл.^6

    Оператор …: spread vs rest (в чём разница)

    • Spread «раскрывает» итерируемые элементы или свойства объекта: передача массива как набора аргументов, копирование/слияние массивов и объектов.^14^15^6
    • Rest «собирает остатки» в массив (в функциях) или объект (при объектной деструктуризации).^5^9

    Примеры «как отличить»:^3

    // spread: раскладывает
    Math.max(...[1,2,3]); // равно Math.max(1,2,3)
    
    // rest: собирает
    function f(a, ...rest) { /* rest это массив оставшихся аргументов */ }
    

    Практические кейсы со spread

    Передача массива как аргументов:^15

    const nums = [1, 2, 3];
    console.log(Math.max(...nums));
    

    Объединение массивов и вставка «посередине»:^14

    const head = [1, 2];
    const mid = [3, 4];
    const tail = [^5];
    const merged = [...head, ...mid, ...tail]; // [1,2,3,4,5]
    

    Клонирование массива/объекта (поверхностная копия):^6

    const a1 = [1,2]; const a2 = [...a1];
    const o1 = { x: 1, y: 2 }; const o2 = { ...o1 }; // поверхностно
    

    Иммутабельные обновления:

    const state = { user: { name: 'A', meta: { age: 30 } } };
    // поверхностное обновление верхнего уровня:
    const next = { ...state, user: { ...state.user, name: 'B' } };
    

    Удаление поля при «копировании»:

    const { password, ...publicUser } = user; // убрать чувствительное поле
    

    Преобразование строки в массив символов:^6

    const chars = [...'Привет']; // ['П','р','и','в','е','т']
    

    Слияние объектов с приоритетом правых свойств:^17

    const base = { role: 'user', active: true };
    const patch = { role: 'admin' };
    const result = { ...base, ...patch }; // role='admin'
    

    Полезные паттерны для React/Node.js/TS

    React props/state:

    function Button({ kind = 'primary', ...props }) {
      return <button className={`btn btn-${kind}`} {...props} />;
    }
    

    Опциональные опции c дефолтами:

    function connectDB({ host='127.0.0.1', port=5432, user, password } = {}) { /* ... */ }
    

    Сужение данных из сложных DTO:

    const { id, profile: { email } = {} } = dto;
    

    TypeScript + деструктуризация:

    • Явные типы переменных после деструктуризации:
    const { id, name }: { id: number; name: string } = user;
    
    • Осторожно: деструктуризация не делает глубокого readonly и не меняет тип вложенных значений.

    Шпаргалка (Cheatsheet)

    • Массивы:
        const [a, b] = arr
        const [first, , third] = arr
        const [head, ...tail] = arr
        [a, b] = [b, a] // swap
        const [x = 1] = []
    
    • Объекты:
       const { x, y } = obj
       const { x: x1, y: y1 } = obj // переименование
       const { x = 0 } = obj // дефолт
       const { a, ...rest } = obj // остаток полей
       const { m: { n } = {} } = obj // безопасная вложенность
    
    • В функциях:
       function f([x, y]) {}
       function g({ a, b = 2 }) {}
       function h(a, ...rest) {} // rest в конце
    
    • Spread:
       fn(...args)
       const merged = [...a1, ...a2]
       const copy = { ...obj }
       const patch = { ...base, override: 1 }
    
    • Частые ошибки:
      • Нельзя два rest-параметра и rest не в конце^9
      • Поверхностное копирование (вложенные объекты всё еще по ссылке)
      • Возможен TypeError при глубокой деструктуризации без дефолтов (читаете undefined.property)
      • Для присваивания в уже объявленные переменные объектной деструктуризации используйте скобки: ({a} = src)

    Расширенные примеры «на все случаи»

    Глубокая деструктуризация массива объектов:

    const list = [
      { id: 1, meta: { tags: ['js','es6'] } },
      { id: 2, meta: { tags: ['node'] } }
    ];
    const [
      { id: firstId, meta: { tags: [firstTag] = [] } = {} },
      { id: secondId, meta: { tags: [, secondTag] = [] } = {} }
    ] = list;
    // firstId=1, firstTag='js', secondId=2, secondTag=undefined
    

    Деструктуризация результата RegExp:

    const [, year, month, day] = /^(\d{4})-(\d{2})-(\d{2})$/.exec('2025-10-27') || [];
    

    Выборка параметров запроса с дефолтами:

    function listUsers(query={}) {
      const {
        page = 1,
        perPage = 20,
        filter: { role = 'all', active = true } = {}
      } = query;
      // ...
    }
    

    Нормализация вложенных ответов API:

    const apiResp = {
      ok: true,
      data: { user: { id: 7, profile: { name: 'Ann' } } }
    };
    const { data: { user: { id, profile: { name } = {} } = {} } = {} } = apiResp || {};
    

    Слияние конфигов без мутаций:^6

    const defaults = { retry: 3, headers: { 'X': 1 } };
    const userCfg = { headers: { 'Y': 2 } };
    const cfg = {
      ...defaults,
      headers: { ...defaults.headers, ...userCfg.headers }
    };
    

    Оптимальная передача аргументов:

    function callMax(arr) { return Math.max(...arr); }
    

    Клонирование без глубокого копирования:

    const arr2 = [...arr1];
    const obj2 = { ...obj1 };
    // вложенные объекты/массивы остаются по ссылке
    

    Важно помнить

    • Деструктуризация ничего не «ломает» справа: она копирует значения в переменные, не изменяя исходную структуру.^1
    • Spread/rest — синтаксис с троеточием, но смысл зависит от контекста:
      • spread: раскрыть итерируемое/объект^8^6
      • rest: собрать остаток в массив/объект^5^9
    • Для устойчивого к ошибкам кода используйте дефолты на промежуточных уровнях вложенности.

    Дополнительные материалы

    • MDN: Деструктурирующее присваивание и Spread syntax^2
    • Современный учебник JavaScript ( learn.javascript.ru ) : деструктуризация и rest/spread^10^5
    • Doka: Деструктуризация и Spread^4
    • Хабр/Обучающие статьи по spread/rest^16^3

    Все приёмы и определения согласованы со спецификой ES6+ и документацией MDN/learn.javascript.ru/Doka.^8^1^4^7^6
    ^18^20^22^24^26^28^30^33^36^38^40^42^44^46^48^50^52^54^57^59^61^63^66^68

    ⁂
    1 ответ Последний ответ
    1
    • MatatabiM Не в сети
      MatatabiM Не в сети
      Matatabi
      написал отредактировано
      #2

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

      1 ответ Последний ответ
      0
      • RocatremR Не в сети
        RocatremR Не в сети
        Rocatrem
        написал отредактировано
        #3

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

        1 ответ Последний ответ
        0

        Категории

        • Главная
        • Новости
        • Фронтенд
        • Бекенд
        • Языки программирования

        Контакты

        • Сотрудничество
        • info@exlends.com
        • Наш чат
        • Наш ТГ канал

        © 2024 - 2025 ExLends, Inc. Все права защищены.

        Политика конфиденциальности
        • Войти

        • Нет учётной записи? Зарегистрироваться

        • Войдите или зарегистрируйтесь для поиска.
        • Первое сообщение
          Последнее сообщение
        0
        • Лента
        • Категории
        • Последние
        • Метки
        • Популярные
        • Пользователи
        • Группы