Приветствую всех! Меня зовут Рома, я разработчик в компании АйТи-Баланс. Хочу поделиться с вами своими знаниями и помочь разобраться в базовых концепциях, которые необходимы каждому новичку в мире JavaScript.
Идея этой статьи возникла из популярного репозитория на GitHub. Я немного адаптировал материал, дополнил его и выделил ключевые аспекты, чтобы сделать информацию максимально доступной и полезной.
Эти базовые концепции особенно важны для тех, кто только начинает свой путь в программировании и хочет стать настоящим разработчиком, а не просто освоить фреймворк по видео и начать фрилансить. Понимание принципов ООП и глубокое знание языка программирования — это то, что необходимо каждому современному разработчику.
Если у вас есть другой опыт или знания, буду рад услышать ваше мнение. А пока я собрал в этой статье основные базовые концепции, которые должен знать каждый JavaScript-разработчик. Эта подборка станет отличным стартом для тех, кто хочет освоить JS и стать профессионалом в своём деле.
Основы ООП (Объектно-Ориентированного Программирования)
ООП — это фундаментальная концепция, которая лежит в основе многих современных языков программирования, включая JavaScript. Вот несколько ключевых аспектов, которые необходимо знать:
Классы и объекты:
Класс — это шаблон или blueprint, который описывает структуру и поведение объектов.
Объект — это экземпляр класса, который наследует свойства и методы этого класса.
Наследование:
Это процесс, при котором один класс наследует свойства и методы другого класса. Это позволяет создавать иерархии классов и повторно использовать код.
Пример:
class Vehicle {
constructor(name) {
this.name = name;
}
displayName() {
return this.name;
}
}
class Car extends Vehicle {
constructor(name, model) {
super(name);
this.model = model;
}
displayModel() {
return `Model: ${this.model}`;
}
}
let car = new Car('Toyota', 'Camry');
console.log(car.displayName() + ' ' + car.displayModel()); // Output: Toyota Model: Camry
Инкапсуляция:
Это механизм, который скрывает внутренние детали объекта и предоставляет контролируемый доступ к ним через методы.
Пример использования геттеров и сеттеров:
class Person {
constructor(name, age) {
this._name = name;
this._age = age;
}
getName() {
return this._name;
}
setName(newName) {
this._name = newName;
}
getAge() {
return this._age;
}
}
let person = new Person('Alice', 30);
console.log(person.getName()); // Output: Alice
person.setName('Bob');
console.log(person.getName()); // Output: Bob
console.log(person.getAge()); // Output: 30
Полиморфизм:
Это способность объекта принимать различные формы. В программировании это означает, что объект подкласса может быть использован вместо объекта суперкласса.
Пример:
class Animal {
makeSound() {
return `The animal makes a generic sound.`;
}
}
class Dog extends Animal {
makeSound() {
return 'The dog barks.';
}
}
let dog = new Dog();
console.log(dog.makeSound()); // Output: The dog barks.
Понимание и освоение этих основ ООП поможет вам создавать более структурированный, гибкий и поддерживаемый код. Эти принципы являются неотъемлемой частью профессионального программирования и часто упускаются в современных курсах.
Что почитать:
Мэтт Вайсфельд "Объектно-ориентированное мышление".
Марейна Хавербеке "Выразительный JavaScript. Современное веб-программирование".
Гради Буч “Объектно-ориентированный анализ и проектирование с примерами приложений”.
Чистый код
Начну с чистого кода, потому что на практике читать код разработчику приходится чаще, чем писать. Чтобы всем было хорошо и удобно, нужно с первой строчки на JS формировать привычку выбирать понятные имена для сущностей, сокращать функции до единственной операции и делать всё прочее, что делает код понятным и простым для восприятия.
Кроме того, не стоит забывать про написание документации. Она играет ключевую роль в поддержке и развитии проекта, особенно в командах с несколькими разработчиками. Хорошо написанная документация помогает новым членам команды быстрее освоиться, а также облегчает поддержку и обновление кода в будущем.
Существует несколько международных стандартов и лучших практик по написанию кода на JavaScript, которые могут служить ориентиром:
Airbnb JavaScript Style Guide: Этот гайд предлагает рекомендации по стилю написания кода, включая соглашения по именованию переменных, форматированию и другим аспектам, которые способствуют созданию чистого и понятного кода.
Google JavaScript Style Guide: Гайд от Google, который также охватывает различные аспекты написания чистого и эффективного кода.
StandardJS: Инструмент для статического анализа кода, который помогает выявлять отклонения от заданных стандартов и поддерживать единый стиль кода в проекте.
ESLint: Инструмент для линтинга JavaScript кода, который позволяет проверять код на соответствие заданным правилам и стандартам.
Эти стандарты и инструменты могут значительно облегчить поддержание чистоты и понятности кода, а также способствовать созданию высококачественных и профессиональных проектов.
Что почитать:
Макконнелл Стив «Совершенный код»
Роберт Дж. Мартин «Чистый код».
Алгоритмы и их сложность
Алгоритмы нужно знать. Понятно, что можно собрать на фреймворке простой сайт без понимания графов и хэшей, только сейчас такие примитивные задачи решают нейросети, а разрабов нанимают для другого. Так что академический минимум: in-place и out-of-place, Big O notation с формированием навыка оценки «на глаз» с учетом неявных данных.
Что почитать:
«Грокаем алгоритмы. Иллюстрированное пособие для программистов и любопытствующих», Бхаргава А.
Типы и структуры данных
Прежде чем писать свои типы данных, нужно разобраться с возможностями, ограничениями, хранением и представлением встроенных. В JS семь примитивов: string, integer, boolean, undefined, symbol, bigint, Null, object и function. Их надо исследовать от и до, к ним же коллекции и глубокое осознание разницы передачи аргументов в функцию по значению и по ссылке, преобразование типов.
Что почитать:
Стек вызовов, callback-функции и асинхронность
В JS функция — это объект. Любую функцию можно пробросить в другую в качестве аргумента, что часто и густо используют для асинхронного выполнения операций. Век сегодня без асинхронности не существует, так что тему колбеков пропускать ни в коем случае нельзя. Хотя бы то, что громадный кусок асинхронного API Node.js работает на коллбэках, уже должно стать аргументом в пользу глубокого погружения в тему.
Что почитать:
Области видимости, IIFE, модули и пространства имен
Области видимости (скоупы) лучше разбирать на куче маленьких практических задач, а потом на кучке поменьше, но уже более сложных. На аналогиях видимость переменных объясняют как физическую возможность увидеть нечто из некоторой точки. Концепция вроде бы простая — находящееся в здании не видно из-за стены, но на практике попытки обращения к переменным вне области видимости и неудачные разграничения скоупов случаются и в практике опытных разрабов.
Области видимости (Scope)
Области видимости в JavaScript играют ключевую роль в управлении доступом к переменным и функциям. Существует два типа областей видимости: глобальная и функциональная.
Глобальная область видимости:
Переменные, объявленные вне какой-либо функции, находятся в глобальной области видимости и доступны из любой части кода в том же файле или даже в других файлах, если они подключены.
Пример:
var globalVariable = 'I am global';
function printGlobal() {
console.log(globalVariable);
}
printGlobal(); // Output: I am global
Функциональная область видимости:
Переменные и функции, объявленные внутри функции, доступны только внутри этой функции. Это предотвращает конфликты имен и помогает изолировать код.
Пример:
function outerFunction() {
var localVariable = 'I am local';
function innerFunction() {
console.log(localVariable);
}
innerFunction(); // Output: I am local
}
var localVariable = 'I am out of function';
outerFunction(); // Output: I am local
Области видимости и замыкания (Closures)
Замыкания — это функции, которые имеют доступ к переменным своей родительской функции, даже после возврата родительской функции. Это мощный инструмент для работы с данными в JavaScript.
Пример замыкания:
function createCounter() {
var count = 0;
return function() {
return count++;
};
}
var counter1 = createCounter();
var counter2 = createCounter();
console.log(counter1()); // Output: 0
console.log(counter2()); // Output: 0
console.log(counter1()); // Output: 1
console.log(counter2()); // Output: 1
IIFE (Immediately Invoked Function Expression)
IIFE — это функция, которая вызывается сразу после ее создания. Это полезно для инкапсуляции кода и создания приватных переменных. Пример IIFE:
(function() {
var privateVariable = 10;
function privateFunction() {
console.log(privateVariable);
}
window.publicFunction = function() {
console.log(privateVariable);
privateFunction();
};
privateFunction();
})();
// publicFunction доступна для использования
publicFunction();
Модули
Модули позволяют разделять код на независимые блоки, которые могут быть импортированы и экспортированы. В JavaScript для этого используются различные подходы:
CommonJS (Node.js):
var module = require('module');
console.log(module);
2. ES6 модули:
import { example } from './example.js';
console.log(example);
Пространства имен (Namespaces)
Пространства имен помогают организовать код и предотвращать конфликты имен. Они могут быть реализованы с использованием объектов:
var myNamespace = {
variable: 'Hello from namespace',
function: function() {
console.log(this.variable);
}
};
myNamespace.function(); // Output: Hello from namespace
Что почитать:
Компактная статья про области видимости на Доке.
You Don't Know JS. Scope & Closures
По-пикабушному простое появление темы замыканий с примерами.
Разница между оператором и выражением
Выражение — возвращает значение, оператор — производит действие. Операторы могут быть частью выражения, но не наоборот. В JS классический набор операторов: присваивания, сравнения, логические, арифметические, строковые и пр.
Пример:
Выражение: x = y + z
В этом выражении 2 оператора: Оператор сложения (+) и оператор присваивания (=).
Что почитать: Краткий справочник по операторам и выражениям на MDN.
Очередь сообщений и цикл событий
В контексте цикла событий (Event Loop) очередь сообщений (The Message Queue) в JavaScript является областью ожидания для функций. Получается, что каждое инициируемое в DOM или пользователем событие и колбеки попадают в общую очередь. Оттуда Event Loop их вытаскивает по мере опустошения стека вызовов, о котором на момент разбора этой темы хорошо бы знать всё и даже больше.
Что почитать: Конспект по микро- и макрозадачам в ДОКЕ.
Рендеринг во всех ипостасях: DOM-дерево и дерево макетов в памяти, перекомпоновка/макеты, композиты и перерисовка
В очень упрощенном виде процесс рендеринга происходит так:
Строится DOM (Document Object Model) — объектное представление.
Происходит анализ таблицы стилей для расчета визуального представления элементов.
Браузер просчитывает лэйауты с учетом стилей и отношений.
Страница отрисовывается на экране.
Формально так всё и происходит, но отвечать на собесе на должность выше стажерской лучше детальнее и точнее с технической точки зрения. К тому же без понимания процесса рендеринга тяжело будет запланировать порядок загрузки и вообще любые асинхронные операции.
Не стоит забывать и о фреймворке — jQuery. А точнее без знаний и понимания работы в нем сейчас не обойтись.
Что почитать:
Статья про работу с DOM (англ.).
jQuery – Введение для начинающих
Прототипное наследование
Наследование в JS работает не совсем так, как в Python или в C++. В отличие от канонического inherit классы в JS не наследуют от других классов, но объекты могут наследовать напрямую друг от друга через прототипы. В двух словах эту концепцию точно описать не получится, да и без практики понять принцип и удобство этой фишки крайне тяжело. Я советую немного почитать и много попробовать строить цепочки прототипов на учебных задачах.
Что почитать: Наследование и цепочки прототипов в формате краткого справочника на MDN.
Фабрики и классы
Класс — это структурированный шаблон, по которому создаются объекты с общими свойствами и набором методов. Фабрика — это сущность, которая возвращает объекты, при этом не являясь шаблоном в его базовом понимании. Сложно? Вот потому этому редко учат на курсах — долго объяснять. На практике применимы оба варианта, но традиционно из-за реализации this и потери контекста фабричные функции выбирают чаще.
Дуглас Крокфорд как-то назвал ООП без классов подарком человечеству от JavaScript. Так или нет — вопрос правильного использования и уместности. В том же React, например, всё строго на классах, но это скорее исключение.
Что почитать: Статья про шаблоны проектирования в «Библиотеке программиста».
Map, reduce, filter и стрелочные функции
В языке JS круто реализована работа с массивами, но популярная ошибка новичка — пользоваться forEach, где надо и не надо. Читать вездесущие переборы — пытка, не надо так делать. Тем более что методы map(), reduce() и filter() в JavaScript не так уж сложны для понимания и даже интуитивны:
map() создает массив с пропущенными через колбэк данными исходного;
reduce() сворачивает структуру, например, через объединение строк, сумму числовых значений и т. п.;
filter() возвращает массив, отфильтрованный через переданный коллбэк, если ни один элемент не пройдет «фейс-контроль», то метод создает пустой массив.
В эту же тему я добавляю стрелочные функции, потому что именно их традиционно используют в качестве колбэков для упомянутых методов маппинга, свертывания и фильтрации.
Массивы в JS имеют очень много всяких различных полезных методов, таких как join, find, shift и unshift, push и pop, и т.д. Поэтому важно иметь под рукой перечни доступных методов (обычно это большие справочники, которые просто полезны для разработчика любого уровня и в которые даже опытным разрабам имеет смысл иногда заглядывать, например).
Что почитать: Статья из библиотеки программиста с примерами по мапам, редьюсам и фильтрам в контексте упрощения кода.
Рекурсия
Рекурсия — понятие из функционального программирования. Рекурсия не императивна, ее результат выполнения удобнее кэшировать, но при этом в неумелых руках она неизбежно вызывает переполнение стека. Если написано непонятно, это повод погрузиться в рекурсию дальше, чем каноническое вычисление производной. Это то, что точно пригодится не только для прохождения собеседования.
Циклы и условия, напротив, являются императивными конструкциями, которые позволяют выполнять повторяющиеся действия или ветвления в зависимости от заданных условий. Циклы, такие как for, while и do-while, позволяют выполнять блок кода до тех пор, пока не будет выполнено определённое условие. Например, цикл for часто используется для итерации по массивам или счётчикам. Условия, представленные операторами if, else и switch, позволяют выполнять различные блоки кода в зависимости от выполнения или невыполнения заданных условий. Эти конструкции являются основой для управления потоком выполнения программы и обеспечивают гибкость в написании кода.
Таким образом, рекурсия, циклы и условия дополняют друг друга, предоставляя мощные инструменты для разработки программного обеспечения.
Что почитать:
Справочная статья по рекурсии на ДОКЕ.
Перевод книги «Выразительный Javascript» в pdf
Онлайн-курс CS50: Introduction to Computer Science
JavaScript: The Good Parts” by Douglas Crockford
Паттерны проектирования и чистая архитектура
Паттерны проектирования лучше знать, чем не знать. Скорее всего, эти знания на старте не пригодятся, зато само их наличие в паре с уместным применением повлияет на скорость роста грейда в положительную сторону. Это как с SOLID и прочими премудростями, которые нерадивые гуру быстрых курсов по войти-в-айти рекомендуют игнорировать. Зря.
Что почитать: справочник по паттернам с примерами в ДОКЕ,
«Чистая архитектура. Искусство разработки программного обеспечения» Мартин Роберт.
Основные принципы программирования: интроспекция и рефлексия. Особенности рефлексии в JavaScript
Интроспекция позволяет изучать атрибуты объекта во время выполнения программы, а рефлексия — манипулировать ими. В статически типизированных языках управлять объектами во время компиляции нельзя, а в JS — можно. Код с рефлексией хуже читается, зато дает гибкость и возможности для метапрограммирования, которых у того же C или Java «из коробки» нет.
Что почитать: Развернутую статью в «Библиотеке программиста» про принципы программирования.
Вывод: перечисленного хватит, чтобы стать настоящим разработчиком?
Фактически каждый, кто пишет код, уже разработчик. Перечисленное — это каркас, на котором проще строить общее понимание сути программирования, учиться, создавать что-то новое. Сейчас на фоне спроса на импортозамещение нужны как раз те, кто может создавать, кто понимает в алгоритмы и эффективное решение задач бизнеса через код.
В статье намеренно приведено буквально по несколько источников информации по каждой концепции, причем источники преимущественно русскоязычные и краткие. Я сделал именно так, чтобы подтолкнуть искать, учиться и пробовать на практике, так продуктивнее и понятнее.
В заключение хочу добавить несколько полезных ссылок, которые всегда могут пригодиться:
Онлайн-компиляторы (например, https://www.programiz.com/javascript/online-compiler/) - всегда помогут проверить работоспособность малых участков кода. Позволяют быстро проверить участок кода, без перезагрузки страницы/пересборки всего кода (иногда эти процессы занимают очень длительное время).
Тестеры регулярных выражений (например, https://regex101.com/). Регулярные выражения очень сильно помогают, когда необходимо проверить текст на соответствие паттерну. Тестеры сразу позволяют увидеть корректен ли построенный шаблон, а также зачастую содержат описание возможных операторов шаблона и примеры построения, что позволяет легко и быстро построить нужный паттерн (например, для валидации корректного ввода email).
alex_k777
jQuery? Are you serious?
ester132
Почитал чем занимается эта фирма, вторым пунктом из услуг является "обновление стека заказчика", думаю там реально без jQuery не обойтись))
Ну а в целом согласен что в современных реалиях это кринж,да даже 10 лет назад это было кринжем
Pab10
Сайт компании на тильде. Сапожник, как говорится, без сапог...