Существует очень тонкая грань между чистым, эффективным кодом и кодом, который может понять только его автор. А хуже всего то, что чётко определить эту грань невозможно. Некоторые программисты в её поисках готовы зайти гораздо дальше других. Поэтому, если нужно сделать некий фрагмент кода таким, чтобы он был бы гарантированно понятен всем, в таком коде обычно стараются не использовать всяческие компактные конструкции вроде тернарных операторов и однострочных стрелочных функций.
Но правда, неприятная правда, заключается в том, что эти вот компактные конструкции часто оказываются очень кстати. И они, при этом, достаточно просты. А это значит, что каждый, кому интересен код, в котором они используются, может их освоить и понять такой код.
В этом материале я собираюсь разобрать некоторые весьма полезные (и иногда выглядящие достаточно таинственными) компактные конструкции, которые могут попасться вам в JavaScript и TypeScript. Изучив их, вы сможете пользоваться ими сами или, как минимум, сможете понять код тех программистов, которые их применяют.
Оператор для проверки значений на
Смысл этого оператора заключается в том, что он возвращает значение правого операнда в том случае, если значение левого равно
Тут задействованы механизмы, очень похожие на те, что используются для организации работы оператора
Оператор, используемый для назначения значения переменной только в том случае, если она имеет значение
Посмотрим на предыдущий фрагмент кода, переписанный с использованием
Оператор
Учитывайте то, что конструкция
Эта возможность имеет отношение исключительно к TypeScript. Поэтому если вы — поборник чистоты JavaScript, то вы многое упускаете. (Шучу, конечно, но к обычному JS такое, и правда, неприменимо).
Как известно, при объявлении класса обычно перечисляют все его свойства с модификаторами доступа, а потом, в конструкторе класса, назначают этим свойствам значения. Но в тех случаях, когда конструктор очень прост, и в нём просто записывают в свойства значения переданных конструктору параметров, можно использовать конструкцию, которая компактнее обычной.
Вот как это выглядит:
Использование вышеописанного подхода при создании конструкторов, определённо, помогает экономить время. Особенно — в том случае, если речь идёт о классе, в котором имеется много свойств.
Тут главное — не забыть добавить
Тернарный оператор — это конструкция, которая читается достаточно легко. Этот оператор часто используют вместо коротких инструкций
В структуре тернарного оператора первым идёт логическое выражение, вторым — нечто вроде команды
Обратите внимание на то, что структура оператора выглядит так же, как и в предыдущем примере. Минус использования тернарного оператора заключается в том, что если в будущем понадобится расширить одну из его частей (либо ту, что относится к истинному значению логического выражения, либо ту, что относится к его ложному значению), это будет означать необходимость перехода к обычной инструкции
В JavaScript (и в TypeScript тоже) логический оператор ИЛИ (
Это значит, что если имеется следующая инструкция
Мы можем воспользоваться этой возможностью и за пределами инструкции
В этом примере продемонстрировано то, как можно пользоваться оператором
Поэтому, если в вашем случае все ложные значения заменять значением, задаваемым по умолчанию, не нужно, вы можете прибегнуть к менее известному оператору
JavaScript-разработчики обычно не особенно стремятся к использованию побитовых операторов. Кого в наши дни интересуют двоичные представления чисел? Но дело в том, что из-за того, что эти операторы работают на уровне битов, они выполняют соответствующие действия гораздо быстрее, чем, например, некие методы.
Если говорить о побитовом операторе НЕ (
Обратите внимание на два значка
Возможности стандарта ES6 упрощают процесс создания объектов и, в частности, процесс назначения значений их свойствам. Если значения свойствам назначаются на основе переменных, имеющих такие же имена, как и эти свойства, тогда повторять эти имена не нужно. Раньше же это было необходимо.
Вот — пример, написанный на TypeScript.
Как видите, новый подход к назначению значений свойствам объектов позволяет писать более компактный и простой код. И такой код при этом читать не сложнее, чем код, написанный по старым правилам (чего не скажешь о коде, написанном с использованием других описанных в этой статье компактных конструкций).
Знаете о том, что однострочные стрелочные функции возвращают результаты вычислений, выполненных в их единственной строке?
Использование этого механизма позволяет избавиться от ненужного выражения
Применение этого приёма необязательно означает усложнение кода. Подобные конструкции представляют собой хороший способ небольшой очистки кода и избавления от ненужных пробелов и лишних строк. Конечно, минус этого подхода заключается в том, что если тела таких вот коротких функций понадобится расширить, придётся снова вернуться к использованию фигурных скобок.
Единственная особенность, которую придётся тут учитывать, заключается в том, что то, что содержится в единственной строке рассматриваемых здесь коротких стрелочных функций, должно быть выражением (то есть — должно выдавать некий результат, который можно вернуть из функции). В противном случае подобная конструкция окажется неработоспособной. Например, вышеописанные однострочные функции нельзя писать так:
В следующем разделе мы продолжим разговор об однострочных стрелочных функциях, но теперь речь пойдёт о таких функциях, при создании которых не обойтись без фигурных скобок.
В ES6 появилась возможность указания значений, которые назначаются параметрам функций по умолчанию. Раньше JavaScript такими возможностями не обладал. Поэтому в ситуациях, когда нужно было назначать параметрам подобные значения, нужно было прибегать к чему-то вроде модели сокращённых вычислений оператора
Но теперь та же задача решается очень просто:
Простой механизм, правда? Но, на самом деле, всё ещё интереснее, чем кажется на первый взгляд. Дело в том, что значением, задаваемым по умолчанию, может быть всё что угодно — включая вызов функции. Эта функция будет вызвана в том случае, если соответствующий параметр при вызове функции передан ей не будет. Это позволяет легко реализовать паттерн обязательных параметров функций:
Вот, собственно говоря, та самая однострочная стрелочная функция, при создании которой не обойтись без фигурных скобок. Дело тут в том, что функция
Этот механизм работает по тому же принципу, что и вышерассмотренная конструкция
Один оператор
Эта короткая конструкция может оказаться полезной в различных ситуациях. Во-первых — когда нужно обеспечить присвоение некоей переменной настоящего логического значения (например, если речь идёт о TypeScript-переменной типа
О механизмах, упомянутых в заголовке этого раздела, можно говорить и говорить. Дело в том, что если пользоваться ими правильно, это может привести к очень интересным результатам. Но тут я не буду идти слишком глубоко. Я расскажу о том, как с их помощью упростить решение некоторых задач.
Приходилось ли вам сталкиваться с задачей записи множества значений свойств объекта в обычные переменные? Эта задача встречается довольно часто. Например — когда надо работать с этими значениями (модифицируя их, например) и при этом не затрагивать то, что хранится в исходном объекте.
Применение деструктурирования объектов позволяет решать подобные задачи, используя минимальные объёмы кода:
Тот, кто пользовался TypeScript, видел этот синтаксис в инструкциях
Например, эта инструкция позволяет импортировать из библиотеки
Использование синтаксиса spread (
Обратите внимание на то, что использование такого подхода к объединению объектов приводит к перезаписи их свойств, имеющих одинаковые имена. К массивам нечто подобное это не относится. В частности, если в объединяемых массивах есть одинаковые значения, все они попадут в результирующий массив. Если от повторов надо избавиться, то можно прибегнуть к использованию структуры данных
Деструктурирование можно использовать вместе с синтаксисом spread. Это позволяет достичь интересного эффекта. Например — убрать первый элемент массива, а остальные не трогать (как в распространённом примере с первым и последним элементом списка, реализацию которого можно найти на Python и на других языках). А ещё, например, можно даже извлечь некоторые свойства из объекта, а остальные оставить нетронутыми. Рассмотрим пример:
Обратите внимание на то, что три точки, используемые в левой части инструкции присвоения значения, должны применяться к самому последнему элементу. Нельзя сначала воспользоваться синтаксисом spread, а потом уже описывать индивидуальные переменные:
Этот код работать не будет.
Существует ещё очень много конструкций, подобных тем, о которых мы сегодня говорили. Но, используя их, стоит помнить о том, что чем компактнее код — тем сложнее его читать тому, кто не привык к применяемым в нём сокращённым конструкциям. И цель применения подобных конструкций — это не минификация кода и не его ускорение. Эта цель заключается лишь в том, чтобы убрать из кода ненужные структуры и облегчить жизнь того, кто будет читать этот код.
Поэтому, чтобы всем было хорошо, рекомендуется поддерживать здоровый баланс между компактными конструкциями и обычным читабельным кодом. Стоит всегда помнить о том, что вы — не единственный человек, который читает ваш код.
Какими компактными конструкциями вы пользуетесь в JavaScript- и TypeScript-коде?
Но правда, неприятная правда, заключается в том, что эти вот компактные конструкции часто оказываются очень кстати. И они, при этом, достаточно просты. А это значит, что каждый, кому интересен код, в котором они используются, может их освоить и понять такой код.
В этом материале я собираюсь разобрать некоторые весьма полезные (и иногда выглядящие достаточно таинственными) компактные конструкции, которые могут попасться вам в JavaScript и TypeScript. Изучив их, вы сможете пользоваться ими сами или, как минимум, сможете понять код тех программистов, которые их применяют.
1. Оператор ??
Оператор для проверки значений на
null
и undefined
(nullish coalescing operator) выглядит как два знака вопроса (??
). С трудом верится в то, что это, с таким-то названием, самый популярный оператор. Правда?Смысл этого оператора заключается в том, что он возвращает значение правого операнда в том случае, если значение левого равно
null
или undefined
. Это не вполне чётко отражено в его названии, ну да ладно, что есть — то есть. Вот как им пользоваться:function myFn(variable1, variable2) {
let var2 = variable2 ?? "default value"
return variable1 + var2
}
myFn("this has ", "no default value") //возвращает "this has no default value"
myFn("this has no ") //возвращает "this has no default value"
myFn("this has no ", 0) //возвращает "this has no 0"
Тут задействованы механизмы, очень похожие на те, что используются для организации работы оператора
||
. Если левая часть выражения равняется null
или undefined
, то возвращена будет правая часть выражения. В противном случае будет возвращена левая часть. В результате оператор ??
отлично подходит для использования в ситуациях, когда некоей переменной может быть назначено всё что угодно, но при этом нужно принять какие-то меры в том случае, если в эту переменную попадёт null
или undefined
.2. Оператор ??=
Оператор, используемый для назначения значения переменной только в том случае, если она имеет значение
null
или undefined
(logical nullish assignment operator), выглядит как два вопросительных знака, за которыми идёт знак «равно» (??=
). Его можно счесть чем-то вроде расширения вышеописанного оператора ??
.Посмотрим на предыдущий фрагмент кода, переписанный с использованием
??=
.function myFn(variable1, variable2) {
variable2 ??= "default value"
return variable1 + variable2
}
myFn("this has ", "no default value") //возвращает "this has no default value"
myFn("this has no ") //возвращает "this has no default value"
myFn("this has no ", 0) //возвращает "this has no 0"
Оператор
??=
позволяет проверить значение параметра функции variable2
. Если оно равняется null
или undefined
, он запишет в него новое значение. В противном случае значение параметра не изменится.Учитывайте то, что конструкция
??=
может показаться непонятной тем, кто с ней не знаком. Поэтому, если вы её используете, вам, возможно, стоит добавить в соответствующем месте кода короткий комментарий с пояснениями.3. Сокращённое объявление TypeScript-конструкторов
Эта возможность имеет отношение исключительно к TypeScript. Поэтому если вы — поборник чистоты JavaScript, то вы многое упускаете. (Шучу, конечно, но к обычному JS такое, и правда, неприменимо).
Как известно, при объявлении класса обычно перечисляют все его свойства с модификаторами доступа, а потом, в конструкторе класса, назначают этим свойствам значения. Но в тех случаях, когда конструктор очень прост, и в нём просто записывают в свойства значения переданных конструктору параметров, можно использовать конструкцию, которая компактнее обычной.
Вот как это выглядит:
//Старый подход...
class Person {
private first_name: string;
private last_name: string;
private age: number;
private is_married: boolean;
constructor(fname:string, lname:string, age:number, married:boolean) {
this.first_name = fname;
this.last_name = lname;
this.age = age;
this.is_married = married;
}
}
//Новый подход, позволяющий сократить код...
class Person {
constructor( private first_name: string,
private last_name: string,
private age: number,
private is_married: boolean){}
}
Использование вышеописанного подхода при создании конструкторов, определённо, помогает экономить время. Особенно — в том случае, если речь идёт о классе, в котором имеется много свойств.
Тут главное — не забыть добавить
{}
сразу после описания конструктора, так как это — представление тела функции. После того, как компилятор встретит такое описание, он всё поймёт и всё остальное сделает сам. Фактически, речь идёт о том, что и первый и второй фрагменты TS-кода будут в итоге преобразованы в один и тот же JavaScript-код.4. Тернарный оператор
Тернарный оператор — это конструкция, которая читается достаточно легко. Этот оператор часто используют вместо коротких инструкций
if…else
, так как он позволяет избавиться от лишних символов и превратить многострочную конструкцию в однострочную.// Исходная инструкция if…else
let isEven = ""
if(variable % 2 == 0) {
isEven = "yes"
} else {
isEven = "no"
}
//Использование тернарного оператора
let isEven = (variable % 2 == 0) ? "yes" : "no"
В структуре тернарного оператора первым идёт логическое выражение, вторым — нечто вроде команды
return
, которая возвращает значение в том случае, если логическое выражение истинно, а третьим — тоже нечто вроде команды return
, возвращающей значение в том случае, если логическое выражение ложно. Хотя тернарный оператор лучше всего использовать в правых частях операций присваивания значений (как в примере), его можно применять и автономно, в виде механизма для вызова функций, когда то, какая функция будет вызвана, или то, с какими аргументами будет вызвана одна и та же функция, определяется значением логического выражения. Вот как это выглядит:let variable = true;
(variable) ? console.log("It's TRUE") : console.log("It's FALSE")
Обратите внимание на то, что структура оператора выглядит так же, как и в предыдущем примере. Минус использования тернарного оператора заключается в том, что если в будущем понадобится расширить одну из его частей (либо ту, что относится к истинному значению логического выражения, либо ту, что относится к его ложному значению), это будет означать необходимость перехода к обычной инструкции
if…else
.5. Использование короткого цикла вычислений, применяемого оператором ||
В JavaScript (и в TypeScript тоже) логический оператор ИЛИ (
||
) реализует модель сокращённых вычислений. То есть — он возвращает первое выражение, оцениваемое как true
, и не выполняет проверку оставшихся выражений.Это значит, что если имеется следующая инструкция
if
, где выражение expression1
содержит ложное значение (приводимое к false
), а expression2
— истинное (приводимое к true
), то вычисленными будут лишь expression1
и expression2
. Выражения espression3
и expression4
вычисляться не будут.if( expression1 || expression2 || expression3 || expression4)
Мы можем воспользоваться этой возможностью и за пределами инструкции
if
, там, где присваиваем переменным некие значения. Это позволит, в частности, записать в переменную значение, задаваемое по умолчанию, в том случае, если некое значение, скажем, представленное параметром функции, оказывается ложным (например — равно undefined
):function myFn(variable1, variable2) {
let var2 = variable2 || "default value"
return variable1 + var2
}
myFn("this has ", " no default value") //возвращает "this has no default value"
myFn("this has no ") //возвращает "this has no default value"
В этом примере продемонстрировано то, как можно пользоваться оператором
||
для записи в переменную либо значения второго параметра функции, либо значения, задаваемого по умолчанию. Правда, если присмотреться к этому примеру, в нём можно увидеть небольшую проблему. Дело в том, что если в variable2
будет значение 0
или пустая строка, то в var2
будет записано значение, задаваемое по умолчанию, так как и 0
и пустая строка приводятся к false
.Поэтому, если в вашем случае все ложные значения заменять значением, задаваемым по умолчанию, не нужно, вы можете прибегнуть к менее известному оператору
??
.6. Двойной побитовый оператор ~
JavaScript-разработчики обычно не особенно стремятся к использованию побитовых операторов. Кого в наши дни интересуют двоичные представления чисел? Но дело в том, что из-за того, что эти операторы работают на уровне битов, они выполняют соответствующие действия гораздо быстрее, чем, например, некие методы.
Если говорить о побитовом операторе НЕ (
~
), то он берёт число, преобразует его в 32-битное целое число (отбрасывая «лишние» биты) и инвертирует биты этого числа. Это приводит к тому, что значение x
превращается в значение -(x+1)
. Чем нам интересно подобное преобразование чисел? А тем, что если воспользоваться им дважды, это даст нам тот же результат, что и вызов метода Math.floor
.let x = 3.8
let y = ~x // x превращается в -(3 + 1), не забывайте о том, что число становится целым
let z = ~y //тут преобразуется y (равное -4) в -(-4 + 1) то есть - в 3
//Поэтому можно поступить так:
let flooredX = ~~x //оба вышеописанных действия выполняются в одной строке
Обратите внимание на два значка
~
в последней строке примера. Может, выглядит это и странно, но, если приходится преобразовывать множество чисел с плавающей точкой в целые числа, этот приём может оказаться очень кстати.7. Назначение значений свойствам объектов
Возможности стандарта ES6 упрощают процесс создания объектов и, в частности, процесс назначения значений их свойствам. Если значения свойствам назначаются на основе переменных, имеющих такие же имена, как и эти свойства, тогда повторять эти имена не нужно. Раньше же это было необходимо.
Вот — пример, написанный на TypeScript.
let name:string = "Fernando";
let age:number = 36;
let id:number = 1;
type User = {
name: string,
age: number,
id: number
}
//Старый подход
let myUser: User = {
name: name,
age: age,
id: id
}
//Новый подход
let myNewUser: User = {
name,
age,
id
}
Как видите, новый подход к назначению значений свойствам объектов позволяет писать более компактный и простой код. И такой код при этом читать не сложнее, чем код, написанный по старым правилам (чего не скажешь о коде, написанном с использованием других описанных в этой статье компактных конструкций).
8. Неявный возврат значений из стрелочных функций
Знаете о том, что однострочные стрелочные функции возвращают результаты вычислений, выполненных в их единственной строке?
Использование этого механизма позволяет избавиться от ненужного выражения
return
. Этот приём часто применяют в стрелочных функциях, передаваемых методам массивов, таким, как filter
или map
. Вот TypeScript-пример:let myArr:number[] = [1,2,3,4,5,6,7,8,9,10]
//Использование длинных конструкций:
let oddNumbers:number[] = myArr.filter( (n:number) => {
return n % 2 == 0
})
let double:number[] = myArr.map( (n:number) => {
return n * 2;
})
//Применение компактных конструкций:
let oddNumbers2:number[] = myArr.filter( (n:number) => n % 2 == 0 )
let double2:number[] = myArr.map( (n:number) => n * 2 )
Применение этого приёма необязательно означает усложнение кода. Подобные конструкции представляют собой хороший способ небольшой очистки кода и избавления от ненужных пробелов и лишних строк. Конечно, минус этого подхода заключается в том, что если тела таких вот коротких функций понадобится расширить, придётся снова вернуться к использованию фигурных скобок.
Единственная особенность, которую придётся тут учитывать, заключается в том, что то, что содержится в единственной строке рассматриваемых здесь коротких стрелочных функций, должно быть выражением (то есть — должно выдавать некий результат, который можно вернуть из функции). В противном случае подобная конструкция окажется неработоспособной. Например, вышеописанные однострочные функции нельзя писать так:
const m = _ => if(2) console.log("true") else console.log("false")
В следующем разделе мы продолжим разговор об однострочных стрелочных функциях, но теперь речь пойдёт о таких функциях, при создании которых не обойтись без фигурных скобок.
9. Параметры функций, которые могут иметь значения, назначаемые по умолчанию
В ES6 появилась возможность указания значений, которые назначаются параметрам функций по умолчанию. Раньше JavaScript такими возможностями не обладал. Поэтому в ситуациях, когда нужно было назначать параметрам подобные значения, нужно было прибегать к чему-то вроде модели сокращённых вычислений оператора
||
.Но теперь та же задача решается очень просто:
//Функцию можно вызвать без 2 последних параметров
//в них могут быть записаны значения, задаваемые по умолчанию
function myFunc(a, b, c = 2, d = "") {
//тут будет логика функции...
}
Простой механизм, правда? Но, на самом деле, всё ещё интереснее, чем кажется на первый взгляд. Дело в том, что значением, задаваемым по умолчанию, может быть всё что угодно — включая вызов функции. Эта функция будет вызвана в том случае, если соответствующий параметр при вызове функции передан ей не будет. Это позволяет легко реализовать паттерн обязательных параметров функций:
const mandatory = _ => {
throw new Error("This parameter is mandatory, don't ignore it!")
}
function myFunc(a, b, c = 2, d = mandatory()) {
// тут будет логика функции...
}
//Отлично работает!
myFunc(1,2,3,4)
//Выдаёт ошибку
myFunc(1,2,3)
Вот, собственно говоря, та самая однострочная стрелочная функция, при создании которой не обойтись без фигурных скобок. Дело тут в том, что функция
mandatory
использует инструкцию throw
. Обратите внимание — «инструкцию», а не «выражение». Но, полагаю, это — не самая высокая плата за возможность оснащать функции обязательными параметрами.10. Приведение любых значений к логическому типу с использованием !!
Этот механизм работает по тому же принципу, что и вышерассмотренная конструкция
~~
. А именно, речь идёт о том, что для приведения любого значения к логическому типу можно воспользоваться двумя логическими операторами НЕ (!!
):!!23 // TRUE
!!"" // FALSE
!!0 // FALSE
!!{} // TRUE
Один оператор
!
уже решает большую часть этой задачи, то есть — преобразует значение к логическому типу, а затем возвращает противоположное значение. А второй оператор !
берёт то, что получилось, и просто возвращает значение, обратное ему. В результате мы и получаем исходное значение, преобразованное к логическому типу.Эта короткая конструкция может оказаться полезной в различных ситуациях. Во-первых — когда нужно обеспечить присвоение некоей переменной настоящего логического значения (например, если речь идёт о TypeScript-переменной типа
boolean
). Во-вторых — когда нужно выполнить строгое сравнение (с помощью ===
) чего-либо с true
или false
.11. Деструктурирование и синтаксис spread
О механизмах, упомянутых в заголовке этого раздела, можно говорить и говорить. Дело в том, что если пользоваться ими правильно, это может привести к очень интересным результатам. Но тут я не буду идти слишком глубоко. Я расскажу о том, как с их помощью упростить решение некоторых задач.
▍Деструктурирование объектов
Приходилось ли вам сталкиваться с задачей записи множества значений свойств объекта в обычные переменные? Эта задача встречается довольно часто. Например — когда надо работать с этими значениями (модифицируя их, например) и при этом не затрагивать то, что хранится в исходном объекте.
Применение деструктурирования объектов позволяет решать подобные задачи, используя минимальные объёмы кода:
const myObj = {
name: "Fernando",
age: 37,
country: "Spain"
}
//Старый подход:
const name = myObj.name;
const age = myObj.age;
const country = myObj.country;
//Использование деструктурирования
const {name, age, country} = myObj;
Тот, кто пользовался TypeScript, видел этот синтаксис в инструкциях
import
. Он позволяет импортировать отдельные методы библиотек и при этом не загрязнять пространство имён проекта множеством ненужных функций:import { get } from 'lodash'
Например, эта инструкция позволяет импортировать из библиотеки
lodash
лишь метод get
. При этом в пространство имён проекта не попадают другие методы этой библиотеки. А их в ней очень и очень много.▍Синтаксис spread и создание новых объектов и массивов на основе существующих
Использование синтаксиса spread (
…
) позволяет упростить задачу создания новых массивов и объектов на основе существующих. Теперь эту задачу можно решить, написав буквально одну строку кода и не обращаясь к каким-то особым методам. Вот пример:const arr1 = [1,2,3,4]
const arr2 = [5,6,7]
const finalArr = [...arr1, ...arr2] // [1,2,3,4,5,6,7]
const partialObj1 = {
name: "fernando"
}
const partialObj2 = {
age:37
}
const fullObj = { ...partialObj1, ...partialObj2 } // {name: "fernando", age: 37}
Обратите внимание на то, что использование такого подхода к объединению объектов приводит к перезаписи их свойств, имеющих одинаковые имена. К массивам нечто подобное это не относится. В частности, если в объединяемых массивах есть одинаковые значения, все они попадут в результирующий массив. Если от повторов надо избавиться, то можно прибегнуть к использованию структуры данных
Set
.▍Совместное использование деструктурирования и синтаксиса spread
Деструктурирование можно использовать вместе с синтаксисом spread. Это позволяет достичь интересного эффекта. Например — убрать первый элемент массива, а остальные не трогать (как в распространённом примере с первым и последним элементом списка, реализацию которого можно найти на Python и на других языках). А ещё, например, можно даже извлечь некоторые свойства из объекта, а остальные оставить нетронутыми. Рассмотрим пример:
const myList = [1,2,3,4,5,6,7]
const myObj = {
name: "Fernando",
age: 37,
country: "Spain",
gender: "M"
}
const [head, ...tail] = myList
const {name, age, ...others} = myObj
console.log(head) //1
console.log(tail) //[2,3,4,5,6,7]
console.log(name) //Fernando
console.log(age) //37
console.log(others) //{country: "Spain", gender: "M"}
Обратите внимание на то, что три точки, используемые в левой части инструкции присвоения значения, должны применяться к самому последнему элементу. Нельзя сначала воспользоваться синтаксисом spread, а потом уже описывать индивидуальные переменные:
const [...values, lastItem] = [1,2,3,4]
Этот код работать не будет.
Итоги
Существует ещё очень много конструкций, подобных тем, о которых мы сегодня говорили. Но, используя их, стоит помнить о том, что чем компактнее код — тем сложнее его читать тому, кто не привык к применяемым в нём сокращённым конструкциям. И цель применения подобных конструкций — это не минификация кода и не его ускорение. Эта цель заключается лишь в том, чтобы убрать из кода ненужные структуры и облегчить жизнь того, кто будет читать этот код.
Поэтому, чтобы всем было хорошо, рекомендуется поддерживать здоровый баланс между компактными конструкциями и обычным читабельным кодом. Стоит всегда помнить о том, что вы — не единственный человек, который читает ваш код.
Какими компактными конструкциями вы пользуетесь в JavaScript- и TypeScript-коде?