Ошибки, которые не учат: на что обратить внимание при изучении JavaScript

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

Привет! Я — Алексей Потюкаев, Software Developer и спикер NIXMultiConf.

У меня есть опыт в проектах, написанных как на чистом JS, так и на различных его фреймворках. Также имеется несколько лет опыта в применении С#. В свободное время я занимаюсь менторством и обучением начинающих разработчиков и выступаю на IT-конференциях.

Мы с вами знаем, что JavaScript — очень объемный язык программирования с различными вспомогательными библиотеками, фреймворками, базами данных и дополнительным функционалом. Нагромождение новой информации может отпугнуть начинающего программиста. Но вспомним слова автора книги «‎Вы не знаете JavaScript» Кайла Симпсона: «‎На JS сначала пишут код, а уже потом выясняют, как он работает» — давайте разберемся, как же его учить.

В этой статье я предлагаю пройтись по основным ошибкам, которые допускают новички при изучении JS. Читайте и запоминайте, на что обратить внимание во время самообучения и на собеседовании.

Учитесь поступательно

Достаточно взглянуть на роадмап разработчика, чтобы убедиться, насколько обширна экосистема JS и как много на первый взгляд надо выучить. Увидев такой массив информации, многие начинающие разработчики сами загоняют себя в ловушку и ошибочно думают, что это все необходимо знать сразу. Они пытаются разобраться со всей около JS экосистемой, не углубляясь в сам JS. Перескакивая между темами, они в итоге знают многое поверхностно. Такой подход не сделает их экспертами ни в одной из областей. Несмотря на то, что JavaScript быстро изменяющийся и растущий язык программирования, он имеет ряд фундаментальных принципов и базовых тем. Они используются и будут использоваться в будущем на проектах любой сложности.

Мое мнение: роадмап начинающего JS-разработчика должен выглядеть примерно так:

По такому плану мы учим основы основ:

  • как работает интернет — думаю, тут не надо объяснять, зачем это знать :)
  • верстку — да, этим тоже приходится регулярно заниматься JS-разработчику;
  • базовый JS — надо не просто знать, как объявить переменную, а все тонкости языка;
  • Git — незнание Git’а может отнимать драгоценное время на решение его проблем во время стажировки на проекте. Проверенный факт :)
  • фреймворк JS — я бы для начала взял React, но советую посмотреть все доступные фреймворки и выбрать себе для старта наиболее привлекательный. А для всех остальных задачи всегда найдутся.

За каждым шагом здесь скрывается обширный массив данных. Разберитесь, чем отличается клиент от сервера, углубитесь в HTML и CSS и определитесь, какой JS-фреймворк (Angular, React или Vue) больше всего соответствует вашим ожиданиям от профессии, и приступайте к обучению вдумчиво. С этими знаниями у вас будет больше шансов успешно пройти первое собеседование. А глубокое понимание основ JavaScript останется с вами на всю жизнь. Отсюда вытекает первое правило: подходите к изучению JavaScript систематически, не распыляйте свое внимание в надежде изучить все и сразу.

Глубоко вникайте в базовые темы

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

const resultA = 40 && 2 || 33;
const resultB = (4 * 2) && (3 * 6);
const resultС = 0 && 2

Зачастую половина начинающих разработчиков, отвечая на вопрос, что будет с переменными a, b, c, допускают ошибки. Многие считают, что тут должны возвращаться булевые значения — true или false. Но при таком коде, если все значения истинные, вернется последнее истинное значение или первое ложное, если хоть бы одно из них ложное. В нашем случае — 2, 18, 0 соответственно. Вот еще пример самой попсовой задачи из мира JS:

for (var i = 0; i < 10; i++)  {
setTimeout ( function ()   {
console.log(i);
} ,   1000)  ;                                                          

Полностью разобравшись лишь с одним этим примером, вы разберетесь и в таких концепциях, как

  • области видимости;
  • замыкания;
  • разница в работе переменных;
  • всплытие переменных;
  • как работает setTimeout и асинхронный JS.

Из этого следует второе правило: разбирая такие примеры, глубже вникайте в решения, которые предлагаются.

Не мыслите «‎стандартами»

Часто на разных ресурсах встречается разделение на «‎старый стандарт JS‎» и «‎‎новый стандарт JS». Якобы фичи из ES6, ES7 и последующих версий JavaScript — это дополнительные инструменты, которые можно выучить, устроившись в команду. У начинающих программистов складывается ошибочное впечатление, что можно учить их по отдельности, но это не так. Все фичи — деструктуризация, стрелочные функции, Spread-операторы, промисы, классы — уже давно используются, как современный стандарт языка. Знать, как с этим работать, крайне необходимо.

Теория без практики — JS на ветер

Допустим, вы прошли свое первое собеседование на вакансию Junior JavaScript Developer и показали потрясающее знание теории. Вас берут на стажировку в команду и доверяют первый таск. И тут вы понимаете, что не в состоянии самостоятельно написать ни строчки кода! Самое время упомянуть о третьем важном правиле: всегда укрепляйте свои теоретические знания на практике. Благодаря систематической практике вы научитесь не только быстро решать прикладные задачи, но и сможете ориентироваться в основных концепциях работы JavaScript. Для потенциальных заказчиков — это ценный скил.

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

const   goodsAddedToCart  -  [ {
name:   'JavaScript' ,
price:   20
}  ,   {

name:   'React' ,
price:   30
} ,   {

name: 'HTML/CSS' ,
price:   202

} ] ;

Уверен, многие новички легко распишут решение через создание цикла при помощи for и переменной result с присвоенным ей нулевым значением. Выглядит не очень изящно, но зато работает, верно?

var  result  =  0;
for   (i = 0;   i   <   goodsAddedToCart.length;   i++)   {
result = result +    goodsAddedToCart[i].price;
} ;

Но как можно переиспользовать этот метод для другой последовательности выбранных товаров — видимо оборачивать это все в функцию, но зачем нам это делать, если JS давно уже предоставляет инструменты для таких задач, вот пример с reduce:

goodsAddedToCart.reduce ( (accumulator,  (  price  } )  =>  accumulator  +  price,   0);

Вот еще пример:

const   getAllPeople  =  async   ()  =>  {
   const  response  =  await   fetch( ‘https://swapi.dev/api/people/’} ;
   const  result = await   response.json(  );
   return  result.results;
} ;

const  displayPersonData = ( person, elementToDisplay) =>  {
const personWrapper  = document.createElement ( ‘div’) ; 
elementToDisplay. appendChild (personWrapper) ;
personWrapper. style. margin  = ‘10 px’ ;

for (let [key, value] of Object. entries (person))  {
   const personInfoField  = personWrapper. appendChild (document createElement( ‘div’)) ;
   personInfoField.innerHTML = ‘S { key}  : $ {value} : ‘ ;  
}

const  displayPeople   =   async   ( )  =>  {
   const   people   =   await   getAllPeople( ) ;
   const   documentBody   =   document.querySelector(  ‘body’  ) ;

document.Body.innerHTML   =   ‘  ‘ ;

people. forEach ( (person)   =>   {
      displayPersonData(person,   documentBody) ;
  } ) ;
} ;

Естественно, этот код можно и дальше улучшать. Однако даже его достаточно, чтобы попрактиковать работу с запросами, массивами, объектами. В интернете есть множество бесплатных API, которые позволяют отрабатывать навыки работы с подобным функционалом. Например, такие ресурсы:

Почему код должен быть лаконичным и понятным

Пренебрежительное отношение к неймингу переменных в коде — еще одна ошибка джунов. Читабельность кода является основным критерием того, что вас поймут другие программисты из вашей команды, в том числе вы сами, вернувшись к коду через пару месяцев. Для примера разберем массив пользователей, каждому из которых присвоено значение имени и возраста:

const  users  = [ {
                                                                      name : ‘John ‘ , 
                                                                      age: 20
                                                                    } , { 
                                                                      name: ‘Alex ‘ , 
                                                                       age: 30
                                                                    } , { 
                                                                        name: ‘Thanos ‘ , 
                                                                         age: 32432
                                                                      } ] ; 
                                                                

Предположим, при работе с данным массивом вы использовали метод обработки Map, что логично, но почему-то вы назвали параметр анонимной функции вы назвали itm:

users.map ( (itm)  =>  {
               // Тут 100 строк кода 
           } ) ;

Почему здесь это следует воспринимать как ошибку, ведь с этим или другим названием переменной все будет работать? Ошибка здесь, конечно же, не программная, а логическая. Если вы работаете с массивом данных users, почему бы не назвать каждый элемент этого массива user? Таким образом вы не будете получать гневные фидбэки от других инженеров о том, что они попросту не понимают, за что отвечает и или иная переменная в коде.

Вот еще один пример ненужного нагромождения символов в коде:

const getPersonAppearance  =  (object) => { 
    const personShortDescription  =  object. name + “ “ +  object. surname + 
         “ in his “ + object. age + “looks awesome”;

         // Тут 100 строк кода 
 
         return { 
             personShortDescription, 
             … 
         } 
      }; 

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

const getPersonAppearance  = ( person ) => { 
                                   const { name, surname, age} = person;
                                   const personShortDescription  =  ‘ S {name} S {surname} in his {age} looks awesome ‘ ;

                                  // Тут 100 строк кода 
                                              return { 
                                                  personShortDescription, 
                                                   … 
                                               } 
                                              }; 

Так мы подошли к четвертому правилу: вырабатывайте хорошие привычки во время обучения, и вам не надо будет привыкать к этому во время работы.

Учитесь учиться

В программировании важно никогда не останавливаться на достигнутом. IT-сфера стремительно развивается: появляются новые фреймворки и метрики работы с данными. Если постепенно не осваивать их, вы рискуете надолго зависнуть в рутинных и однообразных задачах. А ведь вы не за этим пришли в профессию, верно? :) Обладая базовыми навыками программирования на JS, похвалите себя, переведите немного дух и возвращайтесь к изучению полноценного роадмапа по JavaScript.

👍НравитсяПонравилось11
В избранноеВ избранном9
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

const goodsAddedToCart — [ {

Это точно статья ментора?
Если да, то мне жаль подопечных.

А так выглядит, как пиар себя любимого...
Кстати подобное я уже где-то видел, толи хабр, толи медиум...

Уважаемые редакторы DOU, пожалуйста, проверяйте материалы, ибо это полный шлак получается.
А разработчикам DOU не плохо бы что-то сделать с вставкой кода в материал.

Спасибо 👍

я попробовал параллельно изучать 2 фреймворка не похожих друг на друга очень хорошо заходит

Як на мене, початківцям взагалі не варто витрачати забагато часу на вивчення JS. Краще починати одразу з якоїсь з реалізацій WASM. Звісно, якщо ціллю не є весь залишок життя підтримувати кимось колись написане старовинне лайно. JS скоріш за все, вивчити все одно доведеться (рано чи пізно). Але, на моє глибоке переконання, його точно не варто вчити першим. В тих, хто вчить JS як першу мову програмування, занадто часто складається враження, що програмування — це мистецтво розуміння погано написаного коду. По-друге, його особливості варто знати рівно настільки, щоб розуміти, що результат виконання майже будь-якого JS коду майже завжди буде контрінтуітивним, тобто вся система з самого початку спланована і розроблена вкрай погано, тому працювати з нею слід вкрай обережно. Звісно це імха імхаста, але допомагає зберігати ментальне здоров’я. Принаймні мені.

ТС, ось гарне завдання для сіньорів на співбесіді:

console.log(
(![] + [])[+[]] +
(![] + [])[+!+[]] +
([![]] + [][[]])[+!+[] + [+[]]] +
(![] + [])[!+[] + !+[]]
)

хай за 15 хвилин вирахують що виведеться в консоль і пояснять чому:)

Я тихо напоминаю, что для многих синьоров этот путь вполне открыт.

це не завдання для сіньорів, а мозгойобство

мс’є сам ставив цю задачу потоку сіньорів, чи лише сам завалився на першої співбесіді?

я предлагаю пройтись по основным ошибкам
изучениE JS

IMHO потрібно масово писати максимально хріновий код на жс, щоб він помер і фаанг вклали багато кілобаксів у створення нормальної мови для браузера.

Да вроде уже была попытка — Dart.
Притом Dart — это фактически тот же самый JS по синтаксису, отличия минимальные, даже названия большинства функций такие-же как в JS
Но при этом вроде все недостатки JS исправлены.
Даже был браузер — Dartium — в котором поддерживался Dart

И Dart как замена JS не «выстрелил».
Не знаю в чем причина — но не исключаю что то что считается недостатками JS делает его наиболее подходящим языком для браузера.

Но факт остается фактом, google передумал и теперь развивает Flutter и Fuchsia.

P.S. Подозреваю что одна из причин из-за которых не началась постепенная замена JS на Dart — TypeScript
Хоть это тот же самый JS в более красивой обертке, но какие-то ллюсы по сравнению с JS у него есть.

тільки браузери з 1995+ працюють й працюють, даже не второпав, що вони працюють з хріновим кодом на жс а не з якойсь «нормальною мовою»

До речі, Мозіла має непоганий гайд для веб-розробників новачків. Зверніть увагу, що ліворуч є навігаційні лінки (чомусь вони не на кожній сторінці уроків додали Next та Previous). Здається вони усе послідовно виклали, тому можна йти згори по цим лінкам донизу.

Это читаемо

var  result  =  0;
for   (i = 0;   i   <   goodsAddedToCart.length;   i++)   {
result = result +    goodsAddedToCart[i].price;
} ;

Это ещё более читаемо.
Плюс читаемо в одном месте, место-то важное, таким требуется ручная проверка кода, а ещё избегание разночтений.

function getTotalOfCart(){
 var total=0.00;
 for(const item of goodsAddedToCart) total+= item.price; // where's the bloody quantity?
return total;}

Это НЕ читаемо

goodsAddedToCart.reduce ( (accumulator,  (  price  } )  =>  accumulator  +  price,   0);
Кстати, а как оно работает-то (я не спец в JS), ты хочешь сказать, что посреди строчки кода рождаешь переменную accumulator в зоне твоего скрипта видимости? Похоже что да, JS ничего не скажет про отсутствующую переменную, он её создаст. Мало того, места, где ей передаётся начальное значение и где она объявлена — разорваны смысловым кодом. Йодда стайл!

А ведь это всего 1 строчка! Сколько же всего упускается, про****ается, теряется и оооочень долго потом ищется, просто потому что код невозможно читать.

PS. В первом примере начисто упущен момент работы с массивами. Ты вот прям так уверен, что элементы в JS пронумерованы от 0 до lenth? Ой, сюрприз тебя ждёт, когда юзер что-то из корзины удалит.
А за сложение цены без учёта количества — надо прибивать гвоздями за йатца к красной площади. Как минимум за именование переменных. Даже в учебном примере. Ошибка в имени — гарантия ошибки в коде.

accumulator — это параметр функции (колбека), который передаётся редьюсом. И она остаётся в функциональной области видимости этой функции. Тут всё нормально. А вот со скобками напутано. Фигурная закрывающая есть, а открывающей нет. Это вообще классический пример редьюса — суммирование массива.

Я понимаю, что классический. Но ПОСЛЕ выполнения редьюса аккумулятор всё ещё видимый, не так ли? А значит он создан во внешней к коду области видимости. Но поскольку он не в начале строки объявлен, как принято, то при прочтении кода будет затруднительно искать, кто оно и что он такое.

Я ж не говорю, что это не работает. Я говорю, что это отвратительно читается. И никаких преимуществ по сравнению с читаемым кодом не даёт.

Есть случаи, когда именно такие записи воспринимаются при чтении. Но в большинстве случаев вся роль кода — это прописывание противоестественного поведения элементам. И потому логика должна быстро читаться.

Нечитаемый код — просто кусок говна, который нужно нещадно выпиливать, вместе с тем, кто это говно производит. Отдайте этих говнописцев конкуренту, они имеют отрицательную доходность.

Нет, accumulator умирает вместе с редьюсом. Единственный способ для него выжить — это оказаться в скоупе замыкания уже другой функции, но это совсем другая история.
Код гораздо чаще читается, чем пишется, поэтому не могу не согласиться — он обязан быть читаемым. Проблема в том, что на js легко написать код, который будет хоть как-то работать. А многие не хотят сложностей, поэтому и остаются на этом начальном этапе развития, что порождает большое количество говнокода. А аутсорсы готовы платить таким людям хорошие зарплаты, т.к. их задача заработать на людях деньги, а не на коде, который они пишут.

То есть автор, желая показать «простоту», просто удалил «неважные» строчки кода из примера? А ещё спрашивают, почему люди книги покупать перестали. Так поэтому же! Их пишут не специалисты по вопросу, а технические маркетолухские писаки.

Вот тут не понял. Про какие строки речь?

вопрос от застрявшего на начальном этапе развития в js: а чем код с редьюсом (если исправить скобки еще) таки лучше решения с явно описанным циклом, который завернут в функцию?
он более читаем? он быстрее выполняется? js-интерпретатор умеет такое распараллеливать?

я конечно понимаю, выглядит красиво, показывает, что автор чуть умеет в ФП, строк кода меньше в конце концов)) но чем он реально лучше???

я же могу привести привести сразу несколько пунктов, почему он хуже со стороны специалиста, не обладающего глубокими познаниями именно js, но иногда с ним сталкивающегося:
— он на самом деле хуже читаем, чем код с циклом: короткий стрелочный синтаксис замыканий не является интуитивно понятным для не пользующихся им, даже в коде для статьи спец по джс напутал со скобками
— он использует хак с неявной инициализацией переменной, в данной конкретной ситуации это допустимо, но в целом это ужасная практика, которая приводит к появлению очень труднонаходимых ошибок
— код с циклом легко читается как теми, кто использует ООП так и ФП, код с редьюсером естественен только для тех, кто использует ФП

PS я не призываю отказаться от редьюсера, я верю, что именно редьюсер будет скорее всего использоваться джс-спецом, я понимаю, что сейчас в джс доминирует ФП подход, но все же чем этот конкретный код лучше?

явно описанным циклом

Это как сравнивать счёты с калькулятором (плюс/минус :) ). Как по мне такой редьюс выглядит проще, чем цикл. ребята придумали всякие array helpers, в том числе reduce, что, сделать код читабельней и лаконичней. Конечно, если вы видите его 1,5 раза в год, то он вас смущает ) Меня смущал С, когда я с ним знакомился из интереса. Это нормально )

короткий стрелочный синтаксис замыканий

Там не было замыканий. Как автор со скобками напутал не понятно ) IDE такого спасёт.

явно описанным циклом

Please :) здесь нет инициализации переменной. Давайте перепишу
function sum(accumulator, price) {   return accumulator + price; } goodsAddedToCart.reduce(sum, 0);
accumulator и price — это аргументы функции и живут они только в этой функции. Тут абсолютно никаких хаков нет.

код с редьюсером естественен только для тех, кто использует ФП

Я люблю js в том числе за мультипарадигменность. Я не признаю чистую функциональщину, пишу код в ООП стиле следую SOLID, считаю, что dependency inversion — это манна небесная :) но в ту же очередь с удовольствием использую array helpers с их колбеками и другие прелести функциональщины там где это имеет смысл (если бы больше понимал в фп, то скорей всего больше штук использовал, но всё так же наряду с ооп).

но все же чем этот конкретный код лучше?

Простой ответ на простой вопрос — это следующий этап развития. Когда-то были кони, потом стали машины. Когда-то были циклы, потом стали array helpers (уже 6 лет, кстати).
У меня на 50К строк кода текущего проекта (сам делал) 15 редьюсов и 1 reduceRight :) и только 2 классических for цикла. Остальное — for of и гораздо больше мапов и форычей.

спасибо, так
function sum(accumulator, price) {   return accumulator + price; } 
goodsAddedToCart.reduce(sum, 0);
конечно сразу понятно, однострочный вариант с поломанными скобками при первом взгляде чуть вызывает ощущение wtf, было бы хорошо исправить это в статье

Please :) здесь нет инициализации переменной

да, я изначально не понял, что 0 в конце — это начальное значение аккумулятора, которое явно задано как раз, это нужно знать

Да, ошибки в коду обучающего материала — недопустимо. Естественно, без знания, как работают те или иные конструкции оно будет не понятно )

Не исправляйте. Данная ошибка привлекла наше внимание к примеру.

Уже привлекла, уже можно исправлять ) Не каждый будет искать исправленный вариант в комментах

Если исправим, то лишим будущих читателей этого наслаждения — обнаружить несоответствие.

Кстати, а как оно работает-то (я не спец в JS),

Хех, не спец, точнее в глаза не видел, но «уничтожить» и манифест на дофига букаф- месье как всегда в своем репертуаре :)

goodsAddedToCart.reduce ( (accumulator, { price } ) => accumulator + price, 0);

еще как читаемо, как для скромных возможностей рендера доу (если его так можно назвать)- питон вообще сумасшедшее адище в плане семантики, но на нем пишут :D

Похоже что да, JS ничего не скажет про отсутствующую переменную, он её создаст.

то и есть ее объявление. Так она тоже «отсутствующая»?

goodsAddedToCart.reduce ( function reducer(accumulator,  data ) {
 return accumulator  +  data.price;
},   0);
А так? Что, accumulator все еще отсутствующая переменная?
function reducer(accumulator,  data ) {
 return accumulator  +  data.price;
}
goodsAddedToCart.reduce ( reducer,   0);

Пожди, совсем не понимаю. Аккумулятор надо объявлять за пределами редукции, или же он в подобной семантике сам себя объявит? Я ожидал, что отдельного объявления не требуется. Но вот пишут что надо dou.ua/...​ign=reply-comment#2211794
Ты же пишешь, что не надо.

Я, как не JS программист, правильного ответа заранее не знаю. Но сам факт расхождения мнений по весьма простому экземпляру кода, встречающемуся не только лишь везде — уже не просто настораживает, а бьёт в набат.

JS нужно ликвидировать. И как только будет хотя бы намёк на этот тренд — нужно немедленно переходить на новый язык, потому что JS — просто зомби на стероидах, экономически затратный и тошнотворный. Просто в данный момент ему нет серьёзных альтернатив, только надстройки и прочие свистоперделки, не меняющие сути.

JS был хорош как скриптовый язык, для страничек, которым не требовалось особое программирование, лишь небольшие телодвижения вроде реакции на кнопки в 3-5 строчек кода. А не вот это вот всё, требующее ресурсов больше, чем операционная система со всеми службами вместе взятыми.

Но вот пишут что надо

ну зачем же так? ) Там не писали, что надо. Там, как и тут, писали, что accumulator — это аргумент функции, а не переменная, которая неявно объявляется. И я где-то здесь тоже давал пример, что колбек тот с редьюса можно вынести отдельной функцией. Ровно как и в примере выше. Я понимаю, что JS не всем заходит и, что хочется выдать желаемое за действительное, но путать показания всё же не надо )

Зайдём с другой стороны. Сделал свой редьюс, чтоб видно было, как он изнутри рбаотает.

Array.prototype.myReduce = function (callbackFunction, initialValue) {
  let result = initialValue;
  for (const arrayItem of this) { // this === goodsAddedToCart
    result = callbackFunction(result, arrayItem);
  }
  return result;
}
goodsAddedToCart.myReduce((accumulator, price) => accumulator + price, 0); // то же самое
PS здесь намеренно упущен кейс с отсутствием стартового значение для простоты разбора конкретного кейса.

А я ж тебе о чём? В примере

goodsAddedToCart.reduce ( (accumulator, ( price } ) => accumulator + price, 0);

ты ничему не присвоил возвращаемое значение. Легко ли проворонить подобную ошибку? Да элементарно! А вот найти затруднительно.

Я ж почему сразу и спросил, если accumulator копит эту сумму, то должен ли он поставляться извне, или рождается внутри и потом виден снаружи. В данном случае он вообще внутреннее имя и за скобками не виден — что есть вполне кошерный синтаксис, как и в других языках, а значение соответственно должно вернуть всё функциональное выражение целиком.

Ты допустил вторую ошибку, семантическую: назвал переменную accumulator. Соответственно от неё и ждут накопление каких-то данных, притом не обязательно суммы, скорее ожидают объект. Ты ж понимаешь, что программируешь не только на JS, а ещё и на естественном языке, английском в данном случае. Назови ты переменную sum или даже s, от неё будут ждать короткой области видимости. Назвал accumulator — и уже предполагается что-то глобальное или как минимум от крупного объекта.

Посему, повторю утверждение: синтаксический сахар не всегда сахар. Очень часто он превращается в кусок дерьма, просто потому что человеком быстро не читается, либо читается неправильно. Олд-стайл тебе чётко показывает МЕСТО объявления, МЕСТО действия, и (в нормальных языках) весьма чётко определяет область видимости.

Область видимости — чисто условное понятие. Оно не для машины, оно для человека. Машина может связать и чёрта с рогами, задача областей видимости — не выстрелить себе в ногу. Соответственно, если области видимости интуитивно не понятны — приходится извращаться. В JavaSctipt подобным извращением стала мода писать const везде, где только можно, хотя раньше без этого обходились, и вообще всё круто работало.

ты ничему не присвоил возвращаемое значение

ну сорян, если ты не знаешь синтаксиса, то не надо трогать ) return в однострочной стрелочной функции не ставится. Синтаксис такой, ничего плохого в этом не вижу. У меня в примере ошибок нет.

ошибку, семантическую

acc или accumulator — типичное название аргумента в подобных случаях. Не сильно понятно почему accumulator обязательно должен быть глобальным, а sum обязательно локальным.

кусок дерьма, просто потому что человеком быстро не читается

Я на джаве не писал. Как ты думаешь, как легко мне будет читать низкоуровневый код на джаве? Ещё и не тем говном полить можно из-за незнания языка.

Область видимости

Область видимости или scope в js lexically defined, соответственно вполне интуитивно понятен. Не, если ты, конечно, специально его видеть не хочешь, бо тебе язык противен, то это другой разговор )

мода писать const везде

const к области видимости имеет достаточно посредственное отношение. Единственное отличие от var (в отношении скоупа) — это то, что let и const порождают блочный скоуп, что есть крайне хорошо и снимает массу проблем. А const много где пишут, чтобы явно дать понять, что эта переменная меняться не будет. Это не обязательно должно быть число PI. Ты смотришь на объявление переменной и сразу понимаешь, что она нигде не модифицируется. Как по мне вполне логично.

Давай подсуммируем ) Тебе очень не нравится js, ты не один такой, я с этим могу жить и переубеждать никого не планирую ) Если есть вопросы — всегда готов помочь. Но кажется тема себя исчерпала.

Я так и сказал — JS плохой язык. В основном, потому что перерос себя. Для малой автоматизации хорош, для серьёзных дел — ужас.

Присвоить значение ты должен был уже ПОСЛЕ того, как вызвал редукцию. Разумеется, не внутри.

const всё же дань моде, она пройдёт. Львиная кода лежит внутри функций, там вообще заморачиваться не надо особо.

Основная проблема JS — низкая читабельность кода, лёгкость сокрытия ошибок. Тема себя исчерпала до выхода конкурента. Пока конкуренции нет, то и обсуждать нечего, с этим приходится смириться.

Но с чём смиряться НЕЛЬЗЯ —так это с тем, что ТВОЙ код будет плохо читаемый. Нужно максимально избегать неоднозначных конструкций, непонятных имён переменных, и лишних сущностей. Иначе говоря, свой код можно делать хорошим даже на JS. Достаточно лишь читаемость ставить во главу угла.

ты ничему не присвоил возвращаемое значение.

Так а в вашей джаве кому тут присвоили возвращаемое значение? )

int result = numberStream.reduce(1, (x,y)->x * y);
назвал переменную accumulator. Соответственно от неё и ждут накопление каких-то данных, притом не обязательно суммы

Глупость, как минимум потому, что все знают, что примитивные аргументы передаются по значению, а значит только для чтения и ничего накапливать не могут. Ровно тоже в Java, потому что никто не передает в функцию вместо копии int ссылку или указатель на него по умолчанию. Лишь бы к чему прицепиться, притом к тому, что не специфика js.

Я прицепился не к JS, а к именованию переменных автором и демонстрации кода им же. Потому что он не просто написал это в коде, а УЧИТ на данных примерах, как надо.

В твоём коде int result получает значение — так и надо. В его коде этого нет.
К имени переменной я прицепился потому, что автор поднимает тему зоны видимости, а в JS это не всегда очевидно, даже матёрые прогеры творят дичь.

Сложи вместе отсутствие возвращаемого значения + имя, которое говорит что значение удерживается — получишь спрятанную ошибку, которая читается как хороший код, а на деле — не работает.

Кстати, хороший вопрос (ответ я не знаю), если переменные внутри подобного агрегатора объявлены без var, const или let — они окажутся видными за пределами? Я ожидаю что нет, не должны. Но я и от for-цикла этого ждал, а вот поди ж ты. Хотя где мне приходилось по мелочи писать JS, я всегда писал let (оказалось так и правильно).

В твоём коде int result получает значение — так и надо. В его коде этого нет.

если речь не о внутренней функции, а самой reduce- то все еще более странно... ну добавь ’const sum=’ которая нигде потом не используется, если полегчает. Какая это ошибка?

даже матёрые прогеры творят дичь.

Все будут творить дичь в том ЯП, о котором они нифига не знают, при подходе зачем учить- я же джавист, а тут скриптовый JS, который годен только для анимированных часов на сайте :)

Сложи вместе отсутствие возвращаемого значения + имя

Ну да, человек вызывал reduce чтобы не юзать возвращаемое значение. При чем там локальные аргументы функции вообще не понятно.

если переменные внутри подобного агрегатора объявлены без var, const или let — они окажутся видными за пределами

в легаси режиме исполнения кода да- тогда это обращение к глобальному объекту window, на котором в качестве свойств и объявляются все глобальные переменные.
в актуальном strict mode будет выброшено исключение аля x is not defined.
Так еще немного и сделаем с Пєніє мощного джаваскиптера :)

В редюсер передается 2 аргумента: функция (которая будет редюсить) и initialValue, который на первой итерации заходит в аккумулятор — developer.mozilla.org/...​y/Reduce?retiredLocale=uk.
Но однострочный вариант, да еще и с поломанными скобками немного выносит мозг и требует напряжения уже для прочтения кода.
Я очень плотно работал с джс 7-8 лет назад (как раз до появления ES6), но сейчас уже читаю определенные конструкции с трудом.

Аккумулятор надо объявлять за пределами редукции, или же он в подобной семантике сам себя объявит?

В каком это ЯП входные аргументы функции надо еще где то декларировать кроме заголовка функции? Крайне озадачивает замешательство сударя, что может в Джава, в которой есть нечто вроде (metanit.com/java/tutorial/10.5.php)

Stream<Integer> numberStream = Stream.of(-4, 3, -2, 1);
int identity = 1;
int result = numberStream.reduce(identity, (x,y)->x * y);
System.out.println(result);  // 24
чем
int result = numberStream.reduce(1, (x,y)->x * y);
это отличается от
goodsAddedToCart.reduce ( (accumulator, price ) => accumulator + price, 0);

?
Да, в JS функция это обычная переменная.

JS нужно ликвидировать. И как только будет хотя бы намёк на этот тренд — нужно немедленно переходить на новый язык

Так, господин Пєніє обявлил немедленную эвакуацию с JS, все бросаем и трём репозитории))
Да-да 15 лет уже это слышу это от неосиливших :) Сударь там уже перешел со скриптовой джавы во «взрослый» c++?

то JS — просто зомби на стероидах, экономически затратный и тошнотворный

именно так ) потому этот «экономически затратный» и вытесняет джаву со всех щелей. Правда, тут адепты джавы все пытаются тайпскрипты натянуть на все подряд, чтобы хоть видимость кровавой джавы заиметь, но то такое.... перебесяться.

А не вот это вот всё, требующее ресурсов больше, чем операционная система со всеми службами вместе взятыми.

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

Я не хвастаюсь знанием, я спросил как правильно. Да, в Java так, в JS, как выяснилось, тоже, просто автор топика упустил момент присвоения значения.

Предполагать — не в моих правилах, за столько лет я уже научен, что никаких гарантий, что «интуитивно понятное» есть понятное правильно, особенно от творцов JS и его фреймворков. Потому, RTFM.

Увидев новый сахар, я и спросил, что за результат получается от исполнения кода, рождается ли новая переменная. Удивляться я уже тоже разучился, никогда не знаешь, что из маразма может стать новым трендом. Кто Scala в руках держал, тот в цирке не смеётся. Ладно хоть ума хватило быстро бросить и проблеваться.

Эвакуацию с JS я не объявлял. Будет куда — тогда да, очень быстро. А пока ж некуда, движки-то JS жрут.

питон вообще сумасшедшее адище в плане семантики, но на нем пишут

Той момент коли жс головного мозку досяг термінальної стадії.

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

просто поддержу. Я пишу немного на js.
map использую
forEach использую
filter использую
и reduce использовал, до тех пор, пока понял, что сдесь что-то не так. Вроде бы с помощью reduce код должен был бы выглядеть проще, но на самом деле нет. Циклы на for выглядят гораздо проще. Ну тут дело вкуса, если каждый день использовать reduce то наверное можно привыкнуть. Но мне тупо не нравится вид конструкции.

Проблема не когда пишешь, но когда читаешь. Можно и reduce грамотно писать, но это не ради 1 строчки пишется.

Лично мне вместо filter совсем даже не впадло написать if, который будет делать по сути то же самое, но записан лаконично и работать быстрее.

Понимаешь ли, потоковое апи — хорошо для потоков. А для массивом гораздо читабельнее и быстрее работа именно с массивами. Зачем плодить кучу лишних сущностей, если можно тупо классикой написать, и всё понятно, а что непонятно — так комментов добавить. А ну, впиши-ка в стрим-ами коммент, так чтобы читался.

Для меня большая часть бездумно применяемого стрим апи выглядит обфускацией. Никакой пользы.

(я не спец в JS),

ось! це є найголовніше! тому будь-ласочка не треба розказувати про те, що ДжС якийсь там.. (censored) (censored) (censored)
займайтеся джавою, це неймовірно безкінечний всесвіт, а ми зі своїм джаваскриптизерством якось без вас будемо радіти своєму нетипизованому життю, вибачте..

Пропущена } в этом коде

for (var i = 0; i < 10; i++) {
setTimeout ( function () {
console.log(i);
} , 1000) ;
for (var i = 0; i < 10; i++) { setTimeout ( function () { console.log(i); } , 1000) ;

За один только этот пример следовало бы навсегда уничтожить JavaScript, а кто его всуе помянет — тому всё прошлое дерьмо и поддерживать, никакой работы больше не давать, и работать за еду (не каждый день).

А что ещё можно делать с языком, который выполняет не то, что написано в коде, а то что создатели посчитали «правильным»? Разумеется, здесь простой пример, увидеть грабли можно, но мог же быть и более сложный код.

Проблема же ещё и в том, что недопрограммисты учатся на дебильных задачах типа «что выведет код», вместо того чтобы понимать: код пишется для человека в первую очередь, чтобы он мог видеть, что код сделает. Если этого НЕ видно, это НЕ код, а кусок говна, от которого надо избавиться.

ЗЫ. Для тех кто не верит, давайте чуть усложню задачку:

for (let i = 0; i < 10; i++) { setTimeout ( function () { console.log(i); } , 1000) ;

«Для начинающих», не так ли?

Ну начнём того, что альтернатива var существует уже 6 лет. Ну а задачка стала то проще. let со своим блочным скоупом сделал этот пример более очевидным.
Если знать, как работает язык, то всё становится достаточно прозрачным и очевидным. Другая проблема, что большинство не хотят этого знать и именно они порождают код, как в изначальном примере. И когда спрашивают чего здесь будет в логе, то именно для того, чтоб понять сможет ли человек разобраться в этом говнокоде или будет и сам такое писать. Как по мне, научиться писать изначально правильно легче, чем разбираться в чужом говнокоде.

А я о чём? Одинаково написанный код, с одинаковым прочтением, ВНЕЗАПНО компилируется в абсолютно разные конструкции. А именно — var не ожидается порождённым видимым вне цикла, если такое требуется, нормально с точки зрения читаемости сначала объявить переменную, а уже потом порождать цикл, после которого она, естественно, останется живой и доступной.

Ладно, усложняем задачу:

for (i = 0; i < 10; i++) { setTimeout ( function () { console.log(i); } , 1000) ;} 
а ведь такого счастья написаны туевы хучи, и всё оно нуждается в читабельности чтобы быть поддержанным.

А вот это ещё хуже, да ) Эта переменная пойдёт в глобальную область видимости и может наломать немало дров. Я пишу на TypeScript, он значительно облегчает жизнь (оговорюсь — это не даёт право забить на понимание JS). Там такие огрехи отлавливаются быстро и просто. Вообщем-то есть инструменты, которые и с js помогут избежать таких глупых ошибок. Основная фишка — это то, что js писался под работу в браузере и его задача кинуть exception в как можно меньших случаях — пусть юзер лучше получит описание товара NaN, чем страница упадёт.

Я пишу на TypeScript

Вот! Я так и сказал — нужно просто убить язык, который несёт на себе ОГРОМНУЮ ЦЕНУ его изучения, и на порядок выше цену ошибок, потому что как дебильный язык ни учи, ошибки будут.

Тот случай, когда ничего не надо исправлять. Просто сделать новый, на основе существующих наработок. А старый — просто исполнять в режиме совместимости, пусть и ценой замедления. Кому не нравится — тот перепишет код. Кто не перепишет — просто останется с рабочим кодом, но развитие такого проекта будет с каждым годом будет всё дороже.

Моё мнение, как уже говорил — нельзя писать на TypeScript не зная js. Да, ts подстрахует во многих местах от глупых ошибок, но всё же это просто надстройка. Кроме того TS очень гибкий. Там есть тип any, который сводит всю пользу на нет. Есть такая штука, как @ts-ignore, которая ясно говорит, что код ниже скомпилит без проверок. Да и в принципе, если компилятор ругается, то js код на выходе мы всё равно имеем. Я был на TS проекте, где 100500 ошибок компилятора — это норма дела, но скомпилированный код в итоге как-то всё же работал. Ключевое тут «как-то». Так что без знаний js в ts тоже бывает не просто. А сделан так TS тоже не просто так, а для того, чтоб было проще перейти на него с js (моя догадка).

Проблема не в знании JS, а в обманке его лексем. Грубо говоря, то что читается в коде, и то что происходит на самом деле — две большие разницы, и нужно не только знать язык, а ещё и догадываться, что имелось в виду.

Программирование — это не только написание кода, а прежде всего его чтение. Если код не читаемый, или ещё хуже, понимаемый не так, склонный к неявным ошибкам — это ПЛОХОЙ язык, от него надо избавляться. И лучше радикальными революционными мерами, не давая изобретать костыли на «замятие» проблем.

Могу сказать короче: JS === WAT?

Насправді треба починати з найпростішого і поступово збільшувати складність. Але без гайдів чи менторів, у морі інформації дуже легко втопитись.

Якщо ви вирішили спробувати себе у фронтенді, я б радив починати зі скачування VS Code та із вивчення верстки (HTML, CSS). Новачок моментально зможе бачити результат своєї роботи, за якийсь тиждень вже знатиме самі базові речі, зможе зверстати просту веб-сторінку. Швидкий та очевидний результат дуже мотивує.

Потім можна спробувати оживити цю сторінку, причому без базових знань JavaScript, наприклад так:

<div onclick="alert('okey!')">Show alert</div>

Тоді вбудувати в сторінку елементарний код JavaScript і так далі йти шляхом теорія-практика-експерименти. Ну а потім вже можна дійти до якогось React...

З іншого боку, у великих компаніях фронтенд вже давно ділиться на дизайн, верстку, та програмування функціональності (JavaScript/TypeScript). Особисто я зовсім не люблю верстку, мені набагато ближче програмування функціональності...

Ще один варіант, спробувати себе у мануальному тестуванні. Як на мене, це відносно простий старт.

у мануальному тестуванні

В тестировании, вообще-то, уже нужно владеть какими-то знаниями программирования (в т.ч. HTML), иметь представление об SQL, системных сервисах/устройстве сетевых запросов и т.п.
Не обязательно именно помнить всё конечно же, но хотя бы понимать, что именно нужно искать в гугле.

Статья нацелена на тех, кто только начинает изучение JS. И именно у таких читателей будут сложности с запуском кода из примеров, т/к практически каждый из них содержит ошибки. В примере с setTimeout не хватает закрывающей скобки, в примере с reduce перепутаны ( и {, и т/д. Про форматирование уже сказали до меня. Автору обязательно стоит всё это исправить, чтобы эффект от статьи не получился обратным: вместо помощи — еще больше не запутать новичков.

порядок странный. изучать надо то, что сразу сможешь применить — HTML и CSS. потом посложнее — js/jquery. потом изучать, как оно на самом деле работает — объекты, наследование, скоупы и вот это вот все. потом, как дойдет до API — можно начинать разбираться, как работает интернет.
а гит откладывать на потом тоже смысла нет — вот как начали с HTML/CSS, так и с гитом сразу разбирайтесь.

Судя по форматированию блоков кода либо вы, либо разработчики доу пропустили этап «HTML/CSS».

Спасибо за статью, но если бы я не ориентировался вообще в JS и открыл бы данный роадмап, то закрыл бы его к х..рам и пошел таксовать в убер))) Имхо, лучше бы объяснить начинающим, что это экосистема frontend или самые популярные инструменты frontend, но уж никак не полный перечень необходимых знаний для изучения/работы с JS.

А что например в него не должно входить? Как по мне так четкий роадмап

Роадмап хороший, я не спорю, но коммон, давайте будем честны, что для вкатывания в ИТ новичку не нужно сразу учить как минимум Bootstrap, ReactStrap, Material UI, Cypress, Enzyme, Next.js, Apollo, GatsbyJS, React Native, Electron и т.д., которые там стоят рекомендуемые. Иначе это можно учиться бесконечно, а всего знать нормально не будешь

А я смотрю на тот роадмап который предлагает автор, по моему такой должен быть

100%! Оснавная ошибка в подобных статьях — их хорошо понимают те, кто уже знает JS. А те, кто не знает, смотрят на это как на загадочные символы и понимают, что они еще ничего не понимают и это их удручает.

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