Node.js Functions
A function is a reusable block of code used to perform a specific task.
In Node.js, functions are one of the core components of JavaScript and are the basic building blocks of applications.
Node.js inherits all the function features of JavaScript, and they play an important role in its asynchronous programming model.
In JavaScript, a function can be used as an argument to another function. We can define a function first and then pass it, or define the function directly where the argument is passed.
Importance of Functions
- Code Reuse: Avoid rewriting the same logic repeatedly
- Modularity: Break down complex problems into small functions
- Maintainability: Eases debugging and modifying independent functional units
Function Declaration
Use thefunctionkeyword to declare a function.
function greet(name) {
console.log(`Hello, ${name}!`);
}
Function Expression
Assign a function to a variable.
const greet = function(name) {
console.log(`Hello, ${name}!`);
};
Arrow Functions
Concise function expressions introduced by ES6.
const greet = (name) => {
console.log(`Hello, ${name}!`);
};
// 单行箭头函数
const greet = name => console.log(`Hello, ${name}!`);
Types of Functions
1. Regular Functions
The most common form of function, which can have parameters and return values.
function add(a, b) {
return a + b;
}
2. Anonymous Functions
Functions without a name, usually passed as arguments to other functions.
setTimeout(function() {
console.log('This is an anonymous function.');
}, 1000);
3. Callback Functions
Passed as an argument to another function and called after a certain operation completes.
function fetchData(callback) {
setTimeout(() => {
const data = 'Some data';
callback(data);
}, 1000);
}
fetchData((data) => {
console.log(data);
});
Async Functions
From callbacks to Promises.
Example
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
Use the async and await keywords to handle asynchronous operations.
Example
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));
Comparison of Call Methods
| Call Method | Example | Characteristics |
|---|---|---|
| Direct call | greet('Alice') |
The most common way |
| Call as a method | obj.method() |
this points to the calling object |
| Constructor call | new Constructor() |
Creates a new instance |
| Indirect call | greet.call(null, 'Bob') |
Can change the this binding |
Advanced Usage
1. Closures
A closure is a function that can remember and access its lexical scope even when it is executed outside that lexical scope.
Example
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
2. Higher-Order Functions
Functions that accept functions as arguments or return functions.
Example
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 Parameter Handling
Default Parameters
Provide default values for parameters at the time of function declaration.
function greet(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
greet(); // Hello, Guest!
greet('Alice'); // Hello, Alice!
Rest Parameters
Allows an indefinite number of arguments to be represented as an array.
Example
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
Destructured Parameters
Extract data from objects or arrays and assign it to variables.
Example
console.log(`Name: ${name}, Age: ${age}`);
}
const user = { name: 'Alice', age: 30 };
getUserInfo(user); // Name: Alice, Age: 30
Example
Single Responsibility of Functions:Each function should do only one thing, making it easier to test and maintain.
Example
return width * height;
}
Avoid Global Variables:Minimize the use of global variables; use local variables and function parameters instead.
Example
let total = 0;
for (const item of items) {
total += item.price * item.quantity;
}
return total;
}
Use Arrow Functions:Arrow functions are concise and clear, especially when dealing with callback functions.
Example
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
const names = users.map(user => user.name);
console.log(names); // ['Alice', 'Bob']
Error Handling:Use try...catch statements to handle errors that may be thrown.
Example
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);
}
}
Functions as Parameters:Use a function as an argument.
Example
console.log(word);
}
function execute(someFunction, value) {
someFunction(value);
}
execute(say, "Hello");
In the code above, we pass the say function as the first argument of the execute function. What is passed here is not the return value of say, but say itself!
As a result, say becomes the local variable someFunction inside execute, and execute can use the say function by calling someFunction() (with parentheses).
Of course, because say has a parameter, execute can pass such an argument when calling someFunction.
Anonymous Functions:We can pass a function as a variable. But we don't have to go through the "define first, then pass" loop; we can define and pass the function directly within the parentheses of another function:
Example
someFunction(value);
}
execute(function(word){ console.log(word) }, "Hello");
We define the function we intend to pass to execute directly where execute accepts its first argument.
In this way, we don't even need to give the function a name, which is why it's called an anonymous function.
How Function Passing Makes the HTTP Server Work
With this knowledge, let's take another look at our simple yet not-so-simple HTTP server:
Example
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
Now it should look much clearer: we pass an anonymous function to the createServer function.
The same purpose can be achieved with code like this:
Example
function onRequest(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
Function Best Practices
Function Design Principles
- Single Responsibility: A function does only one thing
- Reasonable Naming: Use verb + noun form (e.g.
getUserInfo) - Control Length: Recommended to not exceed 20 lines of code
- Avoid Side Effects: Pure functions are easier to test and maintain
Performance Optimization Tips
Example
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;
};
}
Hands-on Practice
Exercise 1: Create a Temperature Conversion Function
Example
* Convert between Celsius and Fahrenheit
* @param {number} temp - Temperature value
* @param {string} unit - Original unit ('C' or 'F')
* @returns {number} Converted temperature
*/
function convertTemperature(temp, unit) {
// Your code...
}
Exercise 2: Implement a Simple Event Emitter
Example
constructor() {
this.events = {};
}
// Implement the on/emit/off methods
}