JavaScript. Функции, типы данных и методы работы с ними

Примечание: Это статья — конспект моей лекции. В ней описываются ключевые понятия.

Типы данных

Примитивные типы данных в JavaScript:

number: числовое значение, например, 5 или 3.14.
string: строковое значение, например, "Привет" или 'Мир'.
boolean: логическое значение, true или false.
null: специальное значение, представляющее отсутствие значения.
undefined: значение, которое не было присвоено.
symbol (в ECMAScript 6): уникальное и неизменное значение.

Объекты

Объекты в JavaScript представляют собой коллекции пар ключ-значение, где ключи – это строки (или символы), а значения могут быть любого типа данных, включая другие объекты, массивы и функции.

const person = {
name: "John",
age: 30,
isAdmin: false,
greet: function() {
console.log(`Привет, меня зовут ${this.name}!`);
}
};
console.log(person.name); // Вывод: John
console.log(person.age); // Вывод: 30
person.greet(); // Вывод: Привет, меня зовут John!

Объекты могут быть созданы с использованием фигурных скобок {} и заполнены парами ключ-значение.

Доступ к свойствам объекта можно получить с помощью оператора . или квадратных скобок [].

console.log(person.name); // Вывод: John
console.log(person["age"]); // Вывод: 30

Свойства объекта могут быть добавлены или изменены после его создания.

person.country = "USA"; // Добавление нового свойства
person.age = 31; // Изменение значения существующего свойства

Свойства объекта могут быть удалены с помощью оператора delete.

delete person.isAdmin; // Удаление свойства

Свойства объекта могут быть перебраны с использованием циклов или методов перебора.

// Цикл for..in
for (let key in person) {
console.log(key + ": " + person[key]);
}
// Метод Object.keys()
const keys = Object.keys(person);
console.log(keys); // Вывод: ["name", "age", "country"]

Существование свойств в объекте можно проверить с помощью оператора in или метода hasOwnProperty.

console.log("name" in person); // Вывод: true
console.log(person.hasOwnProperty("age")); // Вывод: true

Копирование объектов может быть выполнено с использованием различных методов, таких как Object.assign(), оператор распространения (...) или конструктор Object.

// Object.assign()
const copiedPerson1 = Object.assign({}, person);
// Оператор распространения (spread operator)
const copiedPerson2 = { person };
// Конструктор Object
const copiedPerson3 = new Object(person);

Массивы

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

Массивы могут быть созданы с использованием литерала массива [] или с помощью конструктора new Array().

const numbers = [1, 2, 3, 4, 5]; // Массив чисел
const names = ['John', 'Alice', 'Bob']; // Массив строк
const mixedArray = [1, 'two', true]; // Массив смешанных типов данных
const emptyArray = []; // Пустой массив
// Создание массива с помощью конструктора
const fruits = new Array('apple', 'banana', 'orange');

Элементы массива можно получить, используя индекс элемента. Индексы массивов начинаются с 0.

console.log(numbers[0]); // Вывод: 1console.log(names[1]); // Вывод: Alice

Элементы могут быть добавлены в конец массива с помощью метода push() и удалены с помощью метода pop(). Также элементы могут быть добавлены и удалены из начала массива с помощью методов unshift() и shift().

const colors = ['red', 'green', 'blue'];
colors.push('yellow'); // Добавление элемента в конец массива
console.log(colors); // Вывод: ['red', 'green', 'blue', 'yellow']
colors.pop(); // Удаление последнего элемента массива
console.log(colors); // Вывод: ['red', 'green', 'blue']

Массивы могут быть перебраны с использованием различных методов, таких как цикл for, метод forEach(), цикл for...of и др.

// Использование цикла forfor (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}
// Использование метода forEach()
numbers.forEach((number) => {
console.log(number);
});
// Использование цикла for…of
for (let number of numbers) {
console.log(number);
}

JavaScript предоставляет множество встроенных методов для работы с массивами, таких как concat(), slice(), indexOf(), filter(), map() и многие другие. Эти методы предоставляют функциональность для добавления, удаления, изменения и фильтрации элементов массива.

const numbers1 = [1, 2, 3];
const numbers2 = [4, 5, 6];
const combinedNumbers = numbers1.concat(numbers2); // Объединение массивов
console.log(combinedNumbers); // Вывод: [1, 2, 3, 4, 5, 6]
const slicedNumbers = combinedNumbers.slice(2, 4); // Вырезка подмассива
console.log(slicedNumbers); // Вывод: [3, 4]
const index = combinedNumbers.indexOf(5); // Поиск индекса элемента
console.log(index); // Вывод: 4

Прототипы

Это механизм, который позволяет объектам наследовать свойства и методы других объектов. Каждый объект в JavaScript имеет ссылку на свой прототип, которая используется для поиска свойств и методов, которые не определены непосредственно в самом объекте.

Как работают прототипы:

Каждый объект в JavaScript имеет свой прототип. Прототип объекта – это ссылка на другой объект, известный как “родительский” объект. Когда свойство или метод не найдены в самом объекте, JavaScript автоматически обращается к его прототипу для поиска.

Если свойство или метод не найдены в прототипе объекта, JavaScript продолжает поиск в прототипе этого прототипа, и так далее, пока не будет найдено нужное свойство или метод, либо цепочка прототипов не достигнет конечного объекта null. Эта цепочка прототипов называется “цепочкой прототипов” (prototype chain).

Пример использования прототипов:

// Создание объекта с помощью литерала объекта
const animal = {
type: 'Animal',
sound: function() {
console.log('Издает звук');
}
};
// Создание нового объекта с использованием animal в качестве прототипа
const dog = Object.create(animal);
dog.type = 'Dog'; // Переопределение свойства type для объекта dog
// Вызов метода из прототипа animal
dog.sound(); // Вывод: Издает звук
// Проверка, является ли animal прототипом для dog
console.log(Object.getPrototypeOf(dog) === animal); // Вывод: true

Функции

Позволяют переиспользовать код, упрощают поддержку и читаемость.

Могу быть объявлены несколькими способами.

Function declaration

// Используем ключевое слово function
function greet(name) {
return Hi ${name}
}

Function expression

// Используем стрелочную функци
const greet = (name) => {
return Hi ${name}
}

Функции могут принимать параметры и возвращать значения. Возвращаемое значение — это результат выполнения функции. Этот результат может быть передан обратно в вызывающий код.

const summ = (x, y) => {
return x + y
}
const log = () => {
console.log(summ(1, 2))
}
log() // Результат вывода: 3

Callback functions

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

const button = document.querySelector('#myButton')
function handleClick() {
console.log('Кнопка нажата')
}
button.addEventListener('click', handleClick)

В чем преимущества? Callback-функции позволяют выполнить определенный код после завершения асинхронных операций. Например, загрузка данных или выполнение запросов.

В чем проблема? Вложенные callback-функции могут привести к нечитаемому и трудно поддерживаемому коду, известному как “callback hell”. Этого можно избежать, используя методы, такие как Promises или async/await, которые предлагают более линейный и читаемый подход к обработке асинхронного кода.

Пример “callback hell”:

function fetchData(url, callback) {
setTimeout(() => {
const data1 = 'Данные 1';
callback(data1, (data1, callback) => {
setTimeout(() => {
const data2 = 'Данные 2';
callback(data2, (data2, callback) => {
setTimeout(() => {
const data3 = 'Данные 3';
callback(data3);
}, 1000);
});
}, 1000);
});
}, 1000);
}
fetchData('https://example.com/api', (data1, callback) => {
console.log(data1);
callback(data1, (data2, callback) => {
console.log(data2);
callback(data2, (data3) => {
console.log(data3);
});
});
});

Пример использования промисов для асинхронных запросов:

function fetchData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = 'Данные';
resolve(data);
}, 1000);
});
}
fetchData('https://example.com/api')
.then((data1) => {
console.log(data1);
return fetchData('https://example.com/api');
})
.then((data2) => {
console.log(data2);
return fetchData('https://example.com/api');
})
.then((data3) => {
console.log(data3);
})
.catch((error) => {
console.error('Произошла ошибка:', error);
});

Этот код использует промисы для выполнения асинхронных операций и избегает “callback hell”, предоставляя более линейный и читаемый подход к обработке асинхронных запросов. Каждый .then() блок представляет собой следующую операцию после успешного выполнения предыдущей. Если происходит ошибка, она обрабатывается в блоке .catch().

Прототипы и функции

В JavaScript функции также являются объектами, и у них также есть прототипы. Функции имеют свойство prototype, которое используется при создании объектов с помощью оператора new. Когда объект создается с использованием конструктора функции, прототип этой функции становится прототипом создаваемого объекта.

// Определение конструктора функции
function Person(name) {
this.name = name;
}
// Добавление метода в прототип функции Person
Person.prototype.greet = function() {
console.log(`Привет, меня зовут ${this.name}!`);
};
// Создание объекта с использованием конструктора Person
const person1 = new Person('John');
const person2 = new Person('Alice');
// Вызов метода из прототипа функции Person
person1.greet(); // Вывод: Привет, меня зовут John!
person2.greet(); // Вывод: Привет, меня зовут Alice!