Funciones de Node.js
Una función es un bloque de código reutilizable que se utiliza para realizar una tarea específica.
En Node.js, las funciones son uno de los componentes principales de JavaScript y son la unidad básica para construir aplicaciones.
Node.js hereda todas las características de funciones de JavaScript y juega un papel importante en su modelo de programación asíncrona.
En JavaScript, una función puede usarse como argumento de otra función. Podemos definir primero una función y pasarla, o podemos definirla directamente en el lugar del argumento.
Importancia de las funciones
- Reutilización de código: evita escribir repetidamente la misma lógica
- Modularidad: descompone problemas complejos en funciones pequeñas
- Mantenibilidad: facilita la depuración y modificación de unidades funcionales independientes
Declaración de funciones
Usafunctionla palabra clave para declarar una función.
function greet(name) {
console.log(`Hello, ${name}!`);
}
Expresiones de función
Asignar la función a una variable.
const greet = function(name) {
console.log(`Hello, ${name}!`);
};
Funciones flecha
Expresión de función concisa introducida por ES6.
const greet = (name) => {
console.log(`Hello, ${name}!`);
};
// 单行箭头函数
const greet = name => console.log(`Hello, ${name}!`);
Tipos de funciones
1. Funciones normales
La forma más común de función; puede tener parámetros y valor de retorno.
function add(a, b) {
return a + b;
}
2. Funciones anónimas
Funciones sin nombre, generalmente se pasan como argumentos a otras funciones.
setTimeout(function() {
console.log('This is an anonymous function.');
}, 1000);
3. Funciones callback
Se pasan como argumento a otra función y se llaman después de que se complete alguna operación.
function fetchData(callback) {
setTimeout(() => {
const data = 'Some data';
callback(data);
}, 1000);
}
fetchData((data) => {
console.log(data);
});
Funciones asíncronas
De callbacks a Promise.
Ejemplo
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
Usa las palabras clave async y await para manejar operaciones asíncronas.
Ejemplo
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));
Comparación de formas de invocación
| Forma de invocación | Ejemplo | Características |
|---|---|---|
| Llamada directa | greet('Alice') |
La forma más común |
| Llamada como método | obj.method() |
this apunta al objeto que llama |
| Llamada como constructor | new Constructor() |
Crea una nueva instancia |
| Llamada indirecta | greet.call(null, 'Bob') |
Puede cambiar a qué apunta this |
Uso avanzado
1. Cierres
Un cierre es una función que puede recordar y acceder a su ámbito léxico, incluso cuando se ejecuta fuera de dicho ámbito.
Ejemplo
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
2. Funciones de orden superior
Funciones que aceptan funciones como argumentos o devuelven funciones.
Ejemplo
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
Manejo de parámetros de función
Parámetros por defecto
Proporcionar valores por defecto para los parámetros al declarar la función.
function greet(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
greet(); // Hello, Guest!
greet('Alice'); // Hello, Alice!
Parámetros rest
Permite representar un número indefinido de argumentos como un array.
Ejemplo
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
Desestructuración de parámetros
Extraer datos de un objeto o array y asignarlos a variables.
Ejemplo
console.log(`Name: ${name}, Age: ${age}`);
}
const user = { name: 'Alice', age: 30 };
getUserInfo(user); // Name: Alice, Age: 30
Ejemplo
Responsabilidad única de la función:Cada función debería hacer solo una cosa, así es más fácil de probar y mantener.
Ejemplo
return width * height;
}
Evitar variables globales:Reducir al mínimo el uso de variables globales; usar variables locales y parámetros de función.
Ejemplo
let total = 0;
for (const item of items) {
total += item.price * item.quantity;
}
return total;
}
Usar funciones flecha:Las funciones flecha son concisas y claras, especialmente al manejar callbacks.
Ejemplo
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
const names = users.map(user => user.name);
console.log(names); // ['Alice', 'Bob']
Manejo de errores:Usa la declaración try...catch para manejar errores que puedan lanzarse.
Ejemplo
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);
}
}
Funciones como parámetros:Una función se usa como argumento.
Ejemplo
console.log(word);
}
function execute(someFunction, value) {
someFunction(value);
}
execute(say, "Hello");
En el código anterior, pasamos la función say como el primer argumento de la función execute. Lo que se pasa no es el valor de retorno de say, sino la propia say.
De esta manera, say se convierte en la variable local someFunction dentro de execute, y execute puede usar la función say llamando a someFunction() (con paréntesis).
Por supuesto, como say tiene un parámetro, execute puede pasar ese parámetro al llamar a someFunction.
Funciones anónimas:Podemos pasar una función como variable. Pero no es necesario rodear el círculo de “definir primero, luego pasar”; podemos definir y pasar la función directamente entre los paréntesis de otra función:
Ejemplo
someFunction(value);
}
execute(function(word){ console.log(word) }, "Hello");
Definimos la función que vamos a pasar a execute directamente en el lugar donde execute recibe su primer argumento.
De esta manera, ni siquiera necesitamos darle un nombre a la función; por eso se llama función anónima.
Cómo el paso de funciones hace funcionar al servidor HTTP
Con estos conocimientos, echemos un vistazo a nuestro servidor HTTP sencillo pero no trivial:
Ejemplo
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
Ahora debería verse mucho más claro: pasamos una función anónima a la función createServer.
Con un código como este también se puede lograr el mismo propósito:
Ejemplo
function onRequest(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
Mejores prácticas para funciones
Principios de diseño de funciones
- Responsabilidad única: una función hace solo una cosa
- Nombres adecuados: usar la forma verbo + sustantivo (por ejemplo,
getUserInfo) - Control de longitud: se recomienda no exceder las 20 líneas de código
- Evitar efectos secundarios: las funciones puras son más fáciles de probar y mantener
Consejos de optimización del rendimiento
Ejemplo
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;
};
}
Ejercicios prácticos
Ejercicio 1: Crear una función de conversión de temperatura
Ejemplo
* Implementa la conversión mutua entre grados Celsius y Fahrenheit
* @param {number} temp - Valor de temperatura
* @param {string} unit - Unidad original ('C' o 'F')
* @returns {number} Temperatura convertida
*/
function convertTemperature(temp, unit) {
// Tu código...
}
Ejercicio 2: Implementar un emisor de eventos simple
Ejemplo
constructor() {
this.events = {};
}
// Implementa los métodos on/emit/off
}