Функции Node.js
Функция — это повторно используемый блок кода, предназначенный для выполнения определённой задачи.
В Node.js функции являются одними из основных компонентов JavaScript и базовыми строительными блоками приложений.
Node.js наследует все особенности функций JavaScript, и они играют важную роль в его асинхронной модели программирования.
В JavaScript функцию можно использовать в качестве аргумента другой функции. Мы можем сначала определить функцию, а затем передать её, или определить функцию непосредственно там, где передаётся аргумент.
Важность функций
- Повторное использование кода: Избегайте повторного написания одной и той же логики
- Модульность: Разбивайте сложные задачи на небольшие функции
- Сопровождаемость: Облегчает отладку и изменение независимых функциональных единиц
Объявление функции
Для объявления функции используйте ключевое словоfunction.
function greet(name) {
console.log(`Hello, ${name}!`);
}
Функциональное выражение
Присвойте функцию переменной.
const greet = function(name) {
console.log(`Hello, ${name}!`);
};
Стрелочные функции
Краткие функциональные выражения, введённые в ES6.
const greet = (name) => {
console.log(`Hello, ${name}!`);
};
// 单行箭头函数
const greet = name => console.log(`Hello, ${name}!`);
Типы функций
1. Обычные функции
Наиболее распространённая форма функции, которая может иметь параметры и возвращаемые значения.
function add(a, b) {
return a + b;
}
2. Анонимные функции
Функции без имени, обычно передаваемые как аргументы другим функциям.
setTimeout(function() {
console.log('This is an anonymous function.');
}, 1000);
3. Функции обратного вызова
Передаётся как аргумент другой функции и вызывается после завершения определённой операции.
function fetchData(callback) {
setTimeout(() => {
const data = 'Some data';
callback(data);
}, 1000);
}
fetchData((data) => {
console.log(data);
});
Асинхронные функции
От колбэков к промисам.
Пример
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
Используйте ключевые слова async и await для обработки асинхронных операций.
Пример
try {
const response = await fetch(`https://api.example.com/users/${id}`);
const user = await response.json();
return user;
} catch (error) {
console.error('Error fetching user:', error);
}
}
fetchUser(1).then(user => console.log(user));
Сравнение методов вызова
| Метод вызова | Пример | Характеристики |
|---|---|---|
| Прямой вызов | greet('Alice') |
Самый распространённый способ |
| Вызов как метод | obj.method() |
this указывает на вызывающий объект |
| Вызов конструктора | new Constructor() |
Создаёт новый экземпляр |
| Косвенный вызов | greet.call(null, 'Bob') |
Может изменить привязку this |
Продвинутое использование
1. Замыкания
Замыкание — это функция, которая может запоминать и получать доступ к своей лексической области видимости, даже когда она выполняется вне этой лексической области видимости.
Пример
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
2. Функции высшего порядка
Функции, которые принимают функции в качестве аргументов или возвращают функции.
Пример
return operation(a, b);
}
const sum = applyOperation(5, 3, (x, y) => x + y);
const product = applyOperation(5, 3, (x, y) => x * y);
console.log(sum); // 8
console.log(product); // 15
Обработка параметров функций
Параметры по умолчанию
Указывайте значения по умолчанию для параметров во время объявления функции.
function greet(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
greet(); // Hello, Guest!
greet('Alice'); // Hello, Alice!
Остаточные параметры
Позволяет представить неограниченное количество аргументов в виде массива.
Пример
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
Деструктурированные параметры
Извлекайте данные из объектов или массивов и присваивайте их переменным.
Пример
console.log(`Имя: ${name}, Возраст: ${age}`);
}
const user = { name: 'Alice', age: 30 };
getUserInfo(user); // Имя: Alice, Возраст: 30
Пример
Единственная ответственность функций:Каждая функция должна делать только одну вещь, что упрощает тестирование и поддержку.
Пример
return width * height;
}
Избегайте глобальных переменных:Сведите использование глобальных переменных к минимуму; вместо этого используйте локальные переменные и параметры функций.
Пример
let total = 0;
for (const item of items) {
total += item.price * item.quantity;
}
return total;
}
Использование стрелочных функций:Стрелочные функции кратки и понятны, особенно при работе с функциями обратного вызова.
Пример
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
const names = users.map(user => user.name);
console.log(names); // ['Alice', 'Bob']
Обработка ошибок:Используйте операторы try...catch для обработки ошибок, которые могут быть выброшены.
Пример
try {
const response = await fetch(`https://api.example.com/users/${id}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const user = await response.json();
return user;
} catch (error) {
console.error('Error fetching user:', error);
}
}
Функции как параметры:Используйте функцию в качестве аргумента.
Пример
console.log(word);
}
function execute(someFunction, value) {
someFunction(value);
}
execute(say, "Hello");
В приведённом выше коде мы передаём функцию say в качестве первого аргумента функции execute. Здесь передаётся не возвращаемое значение say, а сама say!
В результате say становится локальной переменной someFunction внутри execute, и execute может использовать функцию say, вызвав someFunction() (с круглыми скобками).
Конечно, поскольку у say есть параметр, execute может передать такой аргумент при вызове someFunction.
Анонимные функции:Мы можем передать функцию как переменную. Но не обязательно проходить через цикл «сначала определить, затем передать»; мы можем определить и передать функцию прямо внутри круглых скобок другой функции:
Пример
someFunction(value);
}
execute(function(word){ console.log(word) }, "Hello");
Мы определяем функцию, которую собираемся передать в execute, прямо там, где execute принимает свой первый аргумент.
Таким образом, нам даже не нужно давать функции имя, поэтому она называется анонимной функцией.
Как передача функций заставляет HTTP-сервер работать
С этими знаниями давайте ещё раз взглянем на наш простой, но не такой уж и простой HTTP-сервер:
Пример
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
Теперь это должно выглядеть гораздо понятнее: мы передаём анонимную функцию в функцию createServer.
Той же цели можно достичь с помощью такого кода:
Пример
function onRequest(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
Лучшие практики работы с функциями
Принципы проектирования функций
- Единственная ответственность: функция выполняет только одну задачу
- Разумное именование: используйте форму глагол + существительное (например,
getUserInfo) - Контроль длины: рекомендуется не превышать 20 строк кода
- Избегайте побочных эффектов: чистые функции проще тестировать и поддерживать
Советы по оптимизации производительности
Пример
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
Практическое занятие
Упражнение 1: Создайте функцию преобразования температуры
Пример
* Преобразование между градусами Цельсия и Фаренгейта
* @param {number} temp - Значение температуры
* @param {string} unit - Исходная единица ('C' или 'F')
* @returns {number} Преобразованная температура
*/
function convertTemperature(temp, unit) {
// Ваш код...
}
Упражнение 2: Реализуйте простой эмиттер событий
Пример
constructor() {
this.events = {};
}
// Реализуйте методы on/emit/off
}