Destructuring - garevna/js-course GitHub Wiki

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

ES6

Деструктуризация - это разложение структуры данных на элементарные составляющие

Структура данных - это совокупность элементов, 
объединенных под одним именем
и организованных по определенному принципу

Фактически структура данных - это именованная капсюла
с четким протоколом доступа к ее содержимому:
в массиве - по индексу элемента массива,
в объекте - по имени свойства

Структуру данных можно "рассыпать" в отдельные переменные
Это и есть деструктуризация

⚠️ Как правило, при деструктуризации имеет место присваивание

В левой части оператора присваивания 
будет перечень переменных
в квадратных или фигурных скобках 
( в зависимости от того, что деструктурируем ),
в правой - массив или объект, 
который мы деструктурируем
Массивы
  • При деструктуризации массива переменные в левой части оператора присваивания должны перечисляться в квадратных скобках

☕ 1

const fruits = [ "банан", "апельсин", "киви" ]
let [ var1, var2, var3 ] = fruits

console.info ( var1 )   // "банан"
console.info ( var2 )   // "апельсин"
console.info ( var3 )   // "киви"

☕ 2

обмен значениями между переменными
let x = 5, y = 7, z = 9
[ x, y, z ] = [ y, z, x ]

console.info ( x )  // 7
console.info ( y )  // 9
console.info ( z )  // 5

☕ 3

Функция getArr возвращает массив
let getArr = deg => [ Math.sin ( deg ), Math.cos ( deg ) ]
получим результат ее работы в переменные sin30 и cos30
let [ sin30, cos30 ] = getArr ( Math.PI/3 )

console.info ( sin30 )  // 0.8660254037844386
console.info ( cos30 )  // 0.5

☕ 4

выборка
let getAngleData = 
    deg => [ 
        Math.sin ( deg ), 
        Math.cos ( deg ), 
        Math.tan ( deg ), 
        Math.atan ( deg ) 
    ]
Вызовем эту функцию, но "пропустим" возвращаемое ею значение тангенса угла:
let [ sin30, cos30, , arctg30 ] = getAngleData ( Math.PI/3 )

console.info ( sin30 )  // 0.8660254037844386
console.info ( cos30 )  // 0.5
console.info ( arctg30 )  // 0.808448792630022

5

Использование деструктурирующего присваивания при сортировке массива

Объявим массив чисел:

var array = [ 5, 1, 4, 9, 3, 8, 0 ]

Выполним следующий код:

array.forEach (
    ( item, index, arr ) => {
        let current = index, prev = index
        while ( --prev >= 0 ) {
            if ( arr [ current ] < arr [ prev ] ) {
                [ arr [ prev ], arr [ current ] ] = 
                    [ arr [ current ], arr [ prev ] ];
                current = prev
            }
        }
    }
)

В результате исходный массив array станет таким:

[0, 1, 3, 4, 5, 8, 9]

Теперь изменим исходный массив:

var array = [ "undefined", "number", "boolean", "string", "function", "symbol", "object" ]

и выполним тот же код

В результате исходный массив станет таким:

["boolean", "function", "number", "object", "string", "symbol", "undefined"]

Объекты

Если мы деструктурируем объект, то переменные в левой части оператора присваивания будут перечисляться в фигурных скобках

⚠️ При этом имена переменных должны совпадать с именами свойств объекта
( порядок следования не имеет значения )

6

const user = { 
    name: "Georg", 
    role: "admin", 
    stars: 5 
}

let { name, role, stars } = user

console.info ( name )   // "Georg"
console.info ( role )   // "admin"
console.info ( stars )  // 5

⚠️ 1️⃣

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

let name, age

( { name, age } = { name: "Ivan", age: 25 } )

В противном случае будет сгенерировано исключение

⛔️ Uncaught SyntaxError: Unexpected token =

⚠️ 2️⃣

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

const user = { 
    login: "Ivan", 
    age: 42, 
    works: true
}

let { 
    login: userName,
    works: employed 
} = user 

console.log( userName )   // "Ivan"
console.log( employed )   // true

⚠️ 3️⃣

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

let {
    login = "Сергей",
    speciality = "слесарь"
} = { login: "Ivan", age: 42 }
 
console.log( login )       // "Ivan"
console.log( speciality )  // "слесарь"

spread ( ... )

Оператор ... позволяет получить:

  • результат деструктуризации массива
  • остаток от дестуктурированного массива

☕ 7

функция getAngleData возвращает массив
let getAngleData = 
    deg => [ 
        Math.sin ( deg ), 
        Math.cos ( deg ), 
        Math.tan ( deg ), 
        Math.atan ( deg ) 
    ]
функция func принимает 4 аргумента
let func = ( x, y, z, w ) => {
    console.log ( x )
    console.log ( y )
    console.log ( z )
    console.log ( w )
}
Передадим результат работы функции getAngleData функции func
func ( ...getAngleData ( Math.PI/3 ) )

// 0.8660254037844386
// 0.5000000000000001
// 1.7320508075688767
// 0.808448792630022

☕ 8

получим остаток массива, возвращаемого функцией getAngleData, в массив rest30
let [ sin30, ...rest30 ] = getAngleData ( Math.PI/3 )

console.info ( sin30 )  // 0.8660254037844386
console.log ( rest30 )  
// (3) [0.5000000000000001, 1.7320508075688767, 0.808448792630022]

☕ 9

разметка
<body>
    <p class="paragraph">1</p>
    <p class="paragraph">2</p>
    <p class="paragraph">3</p>
    <p class="paragraph">4</p>
</body>
код
let collection = document.querySelectorAll ( '.paragraph' )
let [ first, second, third, forth ] = collection
или
let [ first, second, third, forth ] = 
    document.querySelectorAll ( '.paragraph' )
результат
console.log ( first )   // <p class="paragraph">1</p>
console.log ( second )  // <p class="paragraph">2</p>
console.log ( third )   // <p class="paragraph">3</p>
console.log ( forth )   // <p class="paragraph">4</p>

☕ 10

Разметка
<body>
    <button id="registration">Регистрация</button>
    <button id="sign-in">Вход</button>
    <h3 id="title">Hello</h3>
    <div id="demo">
        <p>User name:</p>
        <input id="name"/>
        <p>password:</p>
        <input id="pass" type="password"/>
        <button>Submit</button>
    </div>
</body>
Получить элементы по id
var demo = document.getElementById ( "demo" )
var btnReg = document.getElementById ( "registration" )
var btnSignIn = document.getElementById ( "sign-in" )
var nameElem = document.getElementById ( "name" )
var passElem = document.getElementById ( "pass" )
var title = document.getElementById ( "title" )
Альтернативный вариант
let [ demo, btnReg, btnSignIn, nameElem, passElem, title ] = 
    [ "demo", "registration", "sign-in", "name", "pass", "title" ]
        .map ( item => document.getElementById ( item ) )

☕ 11

Посчитаем, сколько раз встречается каждый символ в строке

Результат поместим в объект, где имя каждого свойства будет буквой, а значение - числом, сколько раз этот символ встречается в строке str

const lettersCounter = str => Object.assign ( {}, 
    ...str.split('')
        .map( letter => {
            return {
                [ letter ]: str.match (eval (`/${letter}/g`)).length
            }
    })
)

lettersCounter ( "htkolkhlfottko" )
результат
▼ {h: 2, t: 3, k: 3, o: 3, l: 2, …}
    f: 1
    h: 2
    k: 3
    l: 2
    o: 3
    t: 3
  ► __proto__: Object

Other samples

☕ 12

function func ( a, b, c ) {
    console.log ( a + b + c )
}

var user = { a: 5, b: 8, c: 13 }
user [ Symbol.iterator ] = function* () {
    yield this.a
    yield this.b
    yield this.c
}

func ( ...user )

☕ 13

var x = [ ..."012345" ]

var x = { ..."012345" }

function func ( a, b, c ) {
    console.log ( a*1 + b*1 + c*1 )
}

func ( ..."578" )


function test ( { a, b, c } = { a: 3, b: 4, c: 5 } ) {
    console.log ( a + b + c )
}

func ()

func ( { a: 5, b: 7, c: 8 } )

Упражнение

Что может вернуть следующий код ( все варианты ):

function first () {
    return Math.random() > 0.5 ? "First" : ""
}
function second () {
    return Math.random() < 0.5 ? "second" : ""
}

second() || console.log ( ...[first(),second()] )

⚠️ **GitHub.com Fallback** ⚠️