Задачка на JavaScript (ES6)

Привет обитателям DOU!

Я тут недавно по долгу службы перешёл на JavaScript и начал знакомство с ES6. В итоге сочинил небольшую задачку, которую и предлагаю порешать. Конструкции не совсем близкие к реальности, ES6 синтаксис вполне валидный. Это всё, конечно, не ново, но для разминки, думаю, будет интересно. Ниже код, который нужно прочитать и сказать, что будет на выходе. Ещё ниже пояснение. Для тех, кто не сильно знаком с ES6 — я буду давать краткие пояснения. Тут далеко не весь ES6, посему за самим стандартом можно пройти по ссылке es6katas.org )
Со всеми замечаниями и уточнениями милости прошу в комменты, не проходите мимо )

'Dangerous - ES6!';
`What's "console.log" gonna log?`;

let misteries = new Array(
    (number) => number,
    (number) => (number),
    (number) => {number},
    (number) => ({number}),
    (number) => {(number)}
);

(function (whatIsMistery = misteries[3](3)) {
    const {number} = whatIsMistery;
    misteries = [...misteries, number];
}());

let results = {};

[0,1,2,3,4].forEach(mistery => results[`mistery${mistery}`] = misteries[mistery](mistery));

results[`mistery${5}`] = misteries[5]

console.log(); // The main question: comment this entire line and tell why!?

(function (...somethingElse) {
    for (let something of somethingElse) console.log(results[`mistery${something}`]);
}(0, 1, 2, 3, 4, 5));

// Check yourself: https://repl.it/languages/javascript/

Итак, поехали разбираться. Что мы видим? Мы видим массив misteries, объявленный через ключевое слово new, хотя можно было воспользоваться литералом, и всё было бы также. Есть пустой объект results, пара ифи (Immediately Invoked Function Expression) и консоль логи.

В массиве misteries лежит 5 стрелочных функций.

Стрелочные функции уменьшают количество кода и сохраняют контекст

var func1 = function(a,b) {
	return a*b
};
var func2 = (a,b) => a*b;
var func3 = (a,b) => {
	return a*b
};
// все 3 функции одинаковые. Если стрелочную функцию можно записать в одну строчку, то ключевое слово return JS подставляет за вас втихую. 
// Если он видит фигурные скобки, то ждёт return.

var myVar = 'window';

var obj = {
 	myVar: 'objVar',
	one: function() {
		console.log(this.myVar) // objVar
	}
};

var obj2 = {
  	myVar: 'objVar',
	one: () => console.log(this.myVar) // window
};

obj.one();
obj2.one();

Вернёмся к функциям позже, т.к. их сейчас всё равно никто не вызывает.

Дальше идёт функция ифи
(function (whatIsMistery = misteries[3](3)) {
    const {number} = whatIsMistery;
    misteries = [...misteries, number];
}());
Она сразу же вызывается без параметров. В аргументах функции стоит дефолтное значение
whatIsMistery = misteries[3](3)

Такое есть и в других языках. Т.е., если мы при вызове функции передадим что-то отличное от undefined, то whatIsMistery будет этим значением. Если нет, то misteries[3](3). При чём эта штука правильно хендлит ситуации когда мы хотим передать null, 0, пустую строку и всё, кроме undefined.

Итак, whatIsMistery = результат выполнения misteries[3] с параметром 3, т.е. (3) => ({number}).

В функции мы видим литерал объекта.

Это просто синтаксический сахар, который эквивалентен

(3) => ({
	number: number
})
Т.е. если мы передаём в функцию какую-нибудь переменную myVar и хотим создать объект, в котором будет поле с названием «myVar» и переданным в функцию значением, то можно воспользоваться литералом объекта для сокращения количества символов.

Функция вернёт объект {number: 3}.

С дефолтным параметром и его результатом разобрались, теперь вернёмся к нашему ифи.

const {number} = whatIsMistery;
Это деструктуризация.

Иными словами мы разбираем конструкцию. Наша конструкция — это объект {number: 3}.
const {number} — создаёт неизменяемую переменную number (там необязательно должен быть const) переменная должна называться так же как и поле нашего объекта. И присваиваться ей должен наш объект. Тогда JS создаст переменную number, пойдёт в whatIsMistery, найдёт поле number и присвоит переменной значение этого поля.

В итоге мы получим переменную number = 3;

Дальше 14 строка misteries = [...misteries, number];
...misteries — Spread operator.

Эта штука упрощает конкатенацию массивов. [1,2,...[3,4],5] = [1,2,3,4,5]

Тут мы переопределяем переменную misteries и складываем в неё всё, что в ней было раньше и добавляем нашу переменную number, которая равна 3.

Строка 19

[0,1,2,3,4].forEach(mistery => results[`mistery${mistery}`] = misteries[mistery](mistery));
Тут мы на лету создаём массив [0,1,2,3,4] и применяем к нему forEach

Это метод массива. Он применяется к массиву и в него передаётся функция. Форыч итеративно выполняет функцию со всеми элементами массива по очереди. В отличие от map он ничего не возвращает, соответственно и return не нужен.

В объекте results мы создаём поля и присваиваем им какие-то значения. В квадратных скобках стоят шаблонные строки

Эти ребята упрощают конкатенацию строк c переменными. Записываются они в обратных кавычках (символ слева от «1»), в них как обычные символы записываются и двойные и одинарные кавычки, и переменные вставляются как ${myVar / 2 + 18}. Операции с переменными происходят внутри скобок, а в строку попадает результат. Т.е. `mistery${mistery}` в первой итерации форыча будет `mistery0`

В первой итерации будет results[`mistery0`] = misteries[0](0)
Во второй results[`mistery1`] = misteries[1](1)
И так далее.

Теперь мы можем вернуться к массиву misteries. Благодаря форычу, в объект results он будет идти со следующими значениями:

let misteries = new Array(
    (0) => number,
    (1) => (number),
    (2) => {number},
    (3) => ({number}),
    (4) => {(number)}
);
(0) => number — вернёт то, что в него передали = 0.
(1) => (number) — тоже самое = 1.
(2) => {number} — эквивалентно записи
(2) => {
	number
}
А значит требует ключевого слова return. Т.к. его нет, то возвращается undefined
(3) => ({number}) — с этим мы уже разобрались, вернётся объект {number, 3}
(4) => {(number)} — то же самое, что (2) => {number}, посему undefined

В строке 21
results[`mistery${5}`] = misteries[5]
Мы в results добавляем поле `mistery${5}` или просто mistery5 и ассайним ему значение misteries[5], которое, как мы уже решили равно намберу 3.

Итого results — это объект

{ mistery0: 0,
  mistery1: 1,
  mistery2: undefined,
  mistery3: { number: 3 },
  mistery4: undefined,
  mistery5: 3 }
В строке 23 стоит console.log(); который выводит на экран пустую стоку и символ переноса строки.

В строке 25 — последний ифи
(function (...somethingElse) {
    for (let something of somethingElse) console.log(results[`mistery${something}`]);
}(0, 1, 2, 3, 4, 5));
Функция незамедлительно вызывается с 6-ю аргументами 0,1,2,3,4,5. В параметрах функции одна переменная — ...somethingElse. Это Rest Parameters

Это все аргументы, переданные в функцию, представленные в виде массива. Т.е.
...somethingElse = [arguments] = Array(arguments) в то время, как arguments — это массиво подобный объект (как будто созданный через new Array()), который содержит в себе аргументы функции и является итерируемым, но не имеет методов массива, то Rest — это настоящий массив.

Внутри функции есть конструкция for of

Конструкция применяется к итерируемым объектам и позволяет обращаться к ним без итератора.

let iterable = [10, 20, 30];
for (let value of iterable) {
    console.log(value);
}
// 10
// 20
// 30

На экран мы выводим results[`mistery${something}`]. Тут тоже шаблонная строка. Something — это наши 0,1,2,3,4,5 => `mistery${something}` = «mistery0» и так дальше, т.е. мы просто выводим всё содержимое объекта results:

0
1
undefined
{ number: 3 }
undefined
3

Основная задача решена, теперь на внимательность. Если убрать консоль лог со строчки 23, то результат получится:

0
1
undefined
{ number: 3 }
undefined
undefined
TypeError: misteries[5] is not a function
    at eval:25:1
    at eval
Мы потеряли number 3 последним элементом results и получили TypeError, что misteries[5], который был 3, а теперь undefined — не функция, что нам и так известно )

Это случается из-за доброты джаваскрипта. Он разрешает нам не ставить семиколоны и ставит их за нас, когда мы забываем. Но, дабы разрешить нам писать красивый код с вайтспейсами, он анализирует код и не добавляет семиколоны в логически незаконченных инструкциях.

В данном случае он ругается на строку 25, где у нас начинается ифи. А в 21 строке
results[`mistery${5}`] = misteries[5]
Я забыл поставить семиколон. JavaScript увидел, что на 25 строке открывается скобка и понял, что это call функции misteries[5] и ругнулся, что это ж не функция.



Спасибо тем, кто дочитал до конца )

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось1
До обраногоВ обраному1
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Хорошая задачка! Все фишки ES6 в одном месте. Извилины запутал нипадеццки. )))

Рад, что кому-то понравилось )

Я что-то не сильно понимаю суть данного топика. Ну есть вот ES6 код. Ну дерьмово он написан. И что дальше? К чему, собственно, сводиться суть обсуждения?

Суть — порешать, если интересно, если вы всё знаете и не интересно — пройти мимо.

походу смысл топика: «Ждите на всех собеседованиях страны»

1. Бесспорно, впечатлили не-ленивостью: такой талмуд накатать, должно было быть вдохновение.
2. По изучению на примерах лучше es6katas.org : и список полнее, и структурировано по разделам.
3. У приведенного вами кода есть проблема: так делать не надо. Я про структуру и читаемость в целом. Понимаю, что цель была «показать как можно больше ES6 в единственном куске кода», но это же убило наглядность. Также, если выбирать между «писать result[`mistery$[5]`]» и «переделать, чтоб не надо было индекс на лету генерировать», первый вариант не пройдет(не могу представить кейс, когда такое предпочтительнее).

Работать с джаваскриптом без вдохновения нельзя )
О том, что конструкции нереальные я сразу предупреждал, как вы правильно заметили, цель была запихнуть побольше и это ж всё-таки задачка, прозрачной её делать неинтересно.
Спасибо за ссылку, там гораздо конструктивней ) Добавлю наверх.

Добавлю наверх.
угу, оно того стОит :) только на меня ссылаться не надо, я ж не автор той системы, просто в закладках лежало — вот, и упомянул.
es6katas.org

это просто праздник для души! столько корнеркейсов!

Підписатись на коментарі