Типичные ошибки начинающих веб-разработчиков на JavaScript
Типичными ошибками мы называем те, которые допускает большинство начинающих веб-программистов на JavaScript. Ведущие разработчики составили список самых распространённых ошибок, чтобы вы обратили на них внимание.
Даниил Хайрутдинов, Ведущий Frontend-разработчик компании MediaSoft
В начале изучения JavaScript, зачастую, не задумываешься, как работает та или иная конструкция языка. Как говорит автор книги «Вы не знаете JS» Кайл Симпсон, на этом языке сначала пишут, а только потом начинают изучать. Из личного опыта курирования стажёров и просмотра тестовых заданий от новичков выделю следующие ошибки:
— Устаревшие конструкции. Например, использование var, хотя этот метод объявления переменных устарел. JS быстро изменяется и за этим необходимо следить.
— Глобальные переменные. В JS можно использовать глобальные переменные, и иногда это нужно. Но использовать их везде, где только можно, – опасный подход. Если другой разработчик или скрипт объявят в проекте глобальную переменную с таким же названием, но с другим значением, произойдет либо подмена переменной, либо просто ошибка.
— Некорректное использование методов перебора массивов. Для перебора массива существует множество методов, но это не значит, что между ними нет разницы. Каждый метод имеет своё назначение. Например, если нужно просто пройти по элементам и вызвать какую-либо стороннюю функцию, то не следует для этого использовать map. Воспользуйтесь, например, forEach:
const products = [1,2,3,4];
// Не хорошо
products.map((id) => fetchProduct(id));
// Хорошо
products.forEach((id) => fetchProduct(id));
Рекомендация эксперта: используйте инструменты, которые делают код более удобочитаемым. Например, ESLint и Prettier. Данные инструменты можно добавить в проект и интегрировать в свою IDE. ESLint уменьшит количество ошибок, а Prettier поможет писать форматированный код и привыкнуть к этому. |
Дмитрий Романовский, Тимлид в компании ADCI Solutions
Мне встречались такие ошибки новичков:
— Не используют строгое сравнение «===» и в результате приведения типов часто получают неожиданные результаты.
— Не используют обработку ошибок. Особенно это опасно, когда JS агрегируются в один файл, и после ошибки все скрипты могут остановиться.
— Пытаются перезаписать const.
— Используют глобальные переменные.
В основном встречаются логические ошибки. Каким-то инструментом их не пофискить. Поэтому остаётся быть внимательным, изучать JavaScript и best practices.
Александр Малиновский, ведущий Frontend-разработчик компании Usetech
— Не интересуются историей того инструмента, на котором они пишут.
Это приводит к непониманию основного функционала.Когда я собеседую джунов, вижу, что большинство из них не знают принципов работы JavaScript, мало того они не понимают зачем им нужно это знать. Потому что базовые вещи, которые от них требуют – это работать на Фреймворке.
Бывает так, что джуну не нужно понимать как это работает «под капотом», какой там язык, как он развивался. Это не ошибка, а простой путь развития джуна, изучающего любой язык программирования, так сказать, в поле.
— Не понимают, как работает V8 движок, под который они пишут код. Что такое функция (из функционального программирования, неблокируемость, асинхронность). Не разбираются в видах типизации (динамическая, строгая).
— Не умеют отлаживать свой продукт. Меня учили, чтобы я умел отлаживать пошагово то, что разрабатываю. Это возможность в любой момент остановить процесс, выяснить, что находится внутри, как это работает и из чего складывается.
— Думают, что callback работает как синхронная функция:
function callback() {
console.log("I am the first");
}
setTimeout(callback, 300);
console.log("I am the last");
// output
// I am the last
// I am the first
Распространенная ошибка разработчиков – неверно истолковывать callback как синхронную функцию. Например, callback, возвращающий значение, которое будет использоваться для других операций.
function addTwoNumbers() {
let firstNumber = 5;
let secondNumber;
setTimeout(function () {
secondNumber = 10;
}, 200);
console.log(firstNumber + secondNumber);
}
addTwoNumbers();
// NaN
При вызове функции addTwoNumbers() произойдёт вычислительная ошибка (NaN)),потому что во время вычисления выражения firstNumber + secondNumber значение переменной secondNumber будет не определено (undefined). Ведь функция, заключенная в setTimeout, выполнится только через 200ms.
Корректным решением здесь будет:
function addTwoNumbers() {
let firstNumber = 5;
let secondNumber;
setTimeout(function () {
secondNumber = 10;
console.log(firstNumber + secondNumber);
}, 200);
}
addTwoNumbers();
// 15
— Неверное использование указателя this:
const obj = {
name: "JavaScript",
printName: function () {
console.log(this.name);
},
printNameIn2Secs: function () {
setTimeout(function () {
console.log(this.name);
}, 2000);
},
};
obj.printName();
// JavaScript
obj.printNameIn2Secs();
// undefined
В первом случае будет выведена строка JavaScript, потому что this.name указывает на конкретное поле объекта. Во втором случае будет выведено undefined, так как this потеряло ссылку как на сам объект, так и на поле объекта.
Это связано с тем, что указатель this напрямую зависит объекта вызова, в контексте которого была вызвана функция.
В нашем случае this в obj.printName() явно указывает на obj. Указатель this в obj.printNameIn2Secs() также указкает на obj. Но this в контексте callback-функции внутри setTimeout не будет.
Чтобы явно указать контекст this, под которым мы хотим вызвать функции в рамках setTimeout, нужно использовать методы bind, call, apply или стрелочную функцию. Классическая анонимная функция не создает свой собственный указатель this, а вместо этого использует глобальный контекст:
const obj = {
name: "JavaScript",
printName: function () {
console.log(this.name);
},
printNameIn2Secs: function () {
setTimeout(() => {
console.log(this.name);
}, 2000);
},
};
obj.printName();
// JavaScript
obj.printNameIn2Secs();
// JavaScript
Эржан Торокулов, наставник курса React.js в Loftschool
Пожалуй, самые распространенные ошибки, которые я встречал:
— Путать Node.js и браузерную среды. Так как JS универсальный язык, который используется как на Frontend, так и на Backend, нужно помнить, что по умолчанию браузерный API недоступен в Node.js, и наоборот, в браузере недоступны возможности/библиотеки Node.js.
Например:
// Серверный (Node.js) код
const http = require('http')
/* Браузерная переменная 'window' тут не существует */
console.log(typeof window) // undefined
console.log(window) // Uncaught ReferenceError: window is not defined
// Браузерный (Фронтенд) код
/* Тут наоборот, Node.js переменной 'process' нет в браузере */
console.log(typeof process) // undefined
console.log(process.env) // Uncaught ReferenceError: process is not defined
— Не знать, что новое, а что старое. JS (EcmaScript) очень стремительно развивается, добавляются новые упрощения синтаксиса (синтаксический сахар), новые API для браузеров. То, что ранее занимало много строк кода, сейчас заменяется одной строчкой, а то, что мы подключали как сторонние npm-библиотеки, сейчас доступно в браузере по умолчанию, если мы говорим о Frontend.
Но многие из этих новомодных “плюшек” могут быть недоступны для пользователей, использующих устаревшие версии браузеров со старым движком JS.
Есть несколько способов решить эту проблему: с помощью полифилов или отдельной сборки для старых и новых браузеров, но это уже другая история.
Например:
const foo = {
bar: 'tada'
}
const baz = {}
/* Optional chaining operator (?.). Доступен не во всех браузерах */
console.log(foo?.bar) // tada
console.log(baz?.bar) // undefined
/* Если запустить в относительно старом браузере (Chrome <79) выше код, то получим */
// Uncaught SyntaxError: Unexpected token '.'
— Путать возможности, добавляемые плагинами. Помимо стандартного синтаксиса и возможностей есть куча babel/webpack плагинов, которые дают ещё немало дополнительных синтаксических упрощений. Новички заблуждаются, думая, что это тоже официальная часть языка или браузерного API.
Например:
// Babel плагин, добавлящий поддержку декораторов - '@babel/plugin-proposal-decorators'
/*
* Сейчас много библиотек/фреймворков используют синтаксис декораторов,
* который ещё на стадии tc39/stage 2
*/
@annotation
class MyClass { }
function annotation(target) {
target.annotated = true;
}
Рекомендация эксперта: Я слышал немало советов, что лучше новичкам сразу стартовать с каких-то JS фреймворков, будь это Frontend (React, Vue, Angular и тд) или Backend/Node.js (Koa.js, Express, Nest.js). Да, это даёт ощущение, что всё легко и новички видят быстрый результат, но минус в том, что многие из них годами продолжают работать, не зная базы. Если знать базу – голый API языка/браузера/Node.js – всё остальное понять и использовать намного легче. Поэтому, если вы сразу начали с фреймворков, надо возвращаться и учить азы JS/Node.js/браузера. Даже если вы не используете их в ежедневной работе. Это придаст уверенности и сделает вас более компетентным специалистом. |
Александр Несвит, наставник профессии «Веб-разработчик» в Loftschool
Я выделю 3 базовые ошибки:
— Изучение фреймворков/библиотек прежде JavaScript. Это неправильный путь в изучении языка. Он сыграет с вами плохую шутку, к примеру, на собеседовании в компанию, которая использует jQuery и чистый JavaScript. С jQuery будет все в порядке, а вот с самим JavaScript возникнут проблемы, так как вы не понимаете принципы работы языка. Мой совет: начните изучение с чистого JavaScript и разбавьте фреймворками. Но соотношение должно быть не 50 на 50, а 70 на 30.
— Нежелание изучать алгоритмы и структуры данных. На старте пути разработчика изучать их детально не обязательно, но знать необходимо. По сути все программы состоят из алгоритмов и структур данных. Их изучение даст базовое понимание работы компьютерных программ и вычислений.
Бонус-совет: Не забывайте про спорт! Писать программы – это круто, но такая деятельность менее подвижна. Вы проводите за монитором практически всё время, а это сказывается на здоровье, самочувствии и не только... Мой совет – составить четкий распорядок дня. Что бы ни случилось, соблюдайте его! Так вы сохраните баланс между работой, здоровьем и отношениями.