© Ирина Кириченко, 2023
ISBN 978-5-0062-0484-3
Создано в интеллектуальной издательской системе Ridero
Все права защищены. Никакая часть этой книги не может быть воспроизведена, передана в какой-либо форме или любыми средствами, электронными или механическими, включая фотокопирование, запись или любые другие системы хранения и передачи информации, без предварительного письменного разрешения владельца авторских прав.
Это практическое руководство представляет собой сборник вопросов и ответов по JavaScript, охватывающих ключевые аспекты языка, важные для подготовки к техническим собеседованиям. От основ до актуальных тем, книга предоставляет обзор основных вопросов, позволяя вам обновить и проверить свои знания. Здесь вы найдете не просто ответы, а инструменты и стратегии для уверенного прохождения собеседований по JavaScript.
Кроме того, это руководство будет полезно для тех, кто хочет освежить свои знания или разобраться в непонятных для себя особенностях языка. Вы найдете здесь не только ответы на типичные вопросы, но и разъяснения сложных концепций, часто встречающихся на собеседованиях. Практические примеры и подробные объяснения помогут вам не только запомнить ключевые моменты, но и понять, как их эффективно применять в реальных проектах.
JavaScript – это высокоуровневый, объектно-ориентированный язык программирования, который используется для создания интерактивных веб-страниц. Он позволяет добавлять различные функциональные возможности на сайты, взаимодействовать с пользователем, обрабатывать данные, анимировать элементы и многое другое. JavaScript является одним из основных инструментов веб-разработки и используется во множестве современных веб-проектах.
Для объявления переменной в JavaScript используются операторы let, const, и (устаревший) var.
let x = 5; // объявление переменной x с помощью let
const PI = 3.14159; // объявление константы PI с помощью const
var y = "Пример"; // объявление переменной y с помощью var
· var является устаревшим методом объявления переменных, он был использован до появления let и const;
· let используется для объявления переменных, значения которых могут изменяться;
· const используется для объявления констант, то есть переменных, значения которых не могут быть изменены после инициализации.
Например:
let count = 10;
count = 20; // Допустимо для let
const PI = 3.14159;
PI = 3; // Недопустимо для const, приведет к ошибке
Кроме того, существуют отличия в области видимости между var, let и const в JavaScript:
· var: Переменные, объявленные с помощью var, имеют функциональную область видимости (function scope). Это означает, что они видны только в функции, в которой были объявлены.
· let и const: Они имеют блочную область видимости (block scope), что означает, что они видны только внутри блока, в котором были объявлены (обычно это блоки кода в фигурных скобках, такие как условия if, циклы for, функции и другие).
Это означает, что переменная, объявленная с помощью var, может быть видна внутри функции, но и за ее пределами, если она не является блочной. В то время как переменные, объявленные с помощью let и const, будут видны только внутри блока кода, в котором были определены.
undefined – это специальное значение, которое получает переменная, если ей не было присвоено никакое значение.
Например:
let x; // переменная x имеет значение undefined
console.log(x); // Выведет: undefined
Основные методы массивов в JavaScript включают push, pop, shift, unshift, map и reduce, filter. Они предоставляют различные способы изменения и обработки элементов в массиве.
Например:
let arr = [1, 2, 3];
arr.push(4); // добавляет элемент в конец массива
arr.pop(); // удаляет последний элемент массива
arr.map(item => item * 2); // создает новый массив, умножая каждый элемент на 2
Замыкание (closure) – это функция, которая имеет доступ к переменным из внешней области видимости, даже после завершения выполнения внешней функции. Это позволяет сохранять доступ к переменным и использовать их внутри вложенной функции.
function outerFunction() {
let outerVariable = 'I am from the outer function';
function innerFunction() {
console.log(outerVariable); // innerFunction имеет доступ к outerVariable из внешней функции
}
return innerFunction;
}
const inner = outerFunction();
inner(); // Выведет: "I am from the outer function"
В JavaScript объекты могут иметь прототипы, из которых они наследуют свойства. Прототип – это механизм, позволяющий объектам наследовать свойства других объектов. JavaScript использует прототипное наследование, где каждый объект имеет ссылку на прототип (другой объект), и он может наследовать свойства этого прототипа.
// Создаем конструктор объекта
function Animal(name) {
this.name = name;
}
// Добавляем метод в прототип объекта Animal
Animal.prototype.sayHello = function () {
console.log("Hello, my name is " + this.name);
};
// Создаем экземпляр объекта Animal
let cat = new Animal("Whiskers");
// Вызываем метод sayHello у объекта cat
cat.sayHello(); // Выводит "Hello, my name is Whiskers"
Стрелочные функции (arrow functions) отличаются от обычных функций тем, что не имеют своего собственного контекста this, используя контекст окружающего кода. Они также короче и автоматически возвращают значение, если оно записано в одну строку без использования фигурных скобок. Однако у стрелочных функций есть ограничения, например, они не могут быть использованы как конструкторы или иметь свои собственные методы this.
const regularFunction = function(a, b) {
return a + b;
};
const arrowFunction = (a, b) => a + b; // Короткий синтаксис для однострочных выражений
// Стрелочная функция с использованием фигурных скобок
const arrowFunctionWithBlock = (a, b) => {
const result = a + b;
return result;
};
Асинхронность в JavaScript – это способ выполнения операций, который не блокирует основной поток выполнения. В JavaScript для работы с асинхронным кодом используются колбэки (callbacks), промисы (promises), async/await и другие методы, позволяющие эффективно управлять асинхронными операциями.
// Пример использования Promise и fetch для асинхронного получения данных
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error fetching data:', error));
// Пример использования async/await
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error fetching data:', error);
}
}
Система обработки ошибок (error handling) в JavaScript позволяет обнаруживать и обрабатывать ошибки в коде. Это включает в себя использование конструкции try…catch, где код, который может вызвать ошибку, помещается в блок try, а обработка ошибки происходит в блоке catch.
function divide(a, b) {
try {
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
} catch (error) {
console.error('Error:', error.message);
}
}
console.log(divide(10, 2)); // Выведет: 5
console.log(divide(10, 0)); // Выведет: "Error: Division by zero"
Hoisting в JavaScript – это механизм, при котором переменные и функции "поднимаются" вверх своей области видимости перед тем, как код начнет выполняться. Это означает, что переменные могут быть объявлены после их использования, а функции могут быть вызваны до их объявления. Однако только объявления переменных и функций поднимаются, а присвоения значений остаются на своих местах.
console.log(myVar); // Выведет: undefined
let myVar = 10;
Синхронный код выполняется последовательно, один шаг за другим, в то время как асинхронный код позволяет выполнить некоторые операции параллельно или отложить их выполнение, продолжая выполнение кода. Преимущества асинхронного кода включают повышение производительности за счет параллельного выполнения операций и предотвращение блокировки потока выполнения, что позволяет приложению быть более отзывчивым.
Event Loop (Цикл событий) – это механизм в JavaScript, который контролирует порядок выполнения кода. Он следит за стеком вызовов и очередью колбэков, перемещая колбэки из очереди в стек при завершении синхронного кода. Это позволяет асинхронному коду выполняться после завершения синхронных операций, не блокируя основной поток выполнения.
Принципы функционального программирования в JavaScript включают использование функций высшего порядка, чистых функций, неизменяемости данных и функций map, filter и reduce для обработки данных. Эти концепции помогают создавать более чистый, модульный и легко поддерживаемый код.
Рассмотрим каждый из этих принципов более детально:
1) Функции первого класса (First-Class Functions). В JavaScript функции являются объектами первого класса, что означает, что их можно присваивать переменным, передавать как аргументы, возвращать из других функций.
const greet = function (name) {
return `Hello, ${name}!`;
};
const sayHello = greet;
console.log(sayHello("John")); // Output: Hello, John!
2) Чистые функции (Pure Functions). Чистая функция возвращает результат, основываясь только на своих аргументах, не имеет побочных эффектов и не зависит от глобального состояния.
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // Output: 5
3) Неизменяемость (Immutability). Изменение состояния может привести к ошибкам и сложностям в отладке. В функциональном программировании ценится неизменяемость данных, и вместо изменения существующих данных создаются новые.
const numbers = [1, 2, 3];
const newNumbers = […numbers, 4]; // создание нового массива с добавлением элемента
console.log(newNumbers); // Output: [1, 2, 3, 4]
4) Функции высшего порядка (Higher-Order Functions). Это функции, которые принимают другие функции в качестве аргументов или возвращают их. Они позволяют абстрагировать операции и создавать более гибкий и читаемый код.
const multiplyBy = function (factor) {
return function (number) {
return number * factor;
};
};
const double = multiplyBy(2);
console.log(double(5)); // Output: 10
5) Рекурсия. Вместо циклов используется рекурсия для выполнения повторяющихся задач. Рекурсивные функции вызывают сами себя с изменяющимися аргументами.
function factorial(n) {
return n === 0 ? 1 : n * factorial(n – 1);
}
console.log(factorial(5)); // Output: 120
6) Функциональные комбинаторы. Это функции, которые комбинируют другие функции, чтобы создавать новые. Примеры включают map, filter, и reduce.
const square = x => x * x;
const increment = x => x + 1;
const squareAndIncrement = compose(increment, square);
console.log(squareAndIncrement(3)); // Output: 10
7) Каррирование (Currying). Процесс преобразования функции с множеством аргументов в цепочку функций, каждая из которых принимает только один аргумент.
const square = x => x * x;
const increment = x => x + 1;
const squareAndIncrement = compose(increment, square);
console.log(squareAndIncrement(3)); // Output: 10