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

function readFilePromise(path) {
  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

async function fetchUser(id) {
    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

function createCounter() {
    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

function applyOperation(a, b, operation) {
    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

function sum(...numbers) {
    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

function getUserInfo({ name, age }) {
    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

function calculateArea(width, height) {
    return width * height;
}

Avoid Global Variables:Minimize the use of global variables; use local variables and function parameters instead.

Example

function calculateTotal(items) {
    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

const users = [
    { 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

async function fetchUser(id) {
    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

function say(word) {
  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

function execute(someFunction, value) {
  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

var http = require("http");

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

var http = require("http");

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

  1. Single Responsibility: A function does only one thing
  2. Reasonable Naming: Use verb + noun form (e.g.getUserInfo)
  3. Control Length: Recommended to not exceed 20 lines of code
  4. Avoid Side Effects: Pure functions are easier to test and maintain

Performance Optimization Tips

Example

// Use closure to cache results
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

class EventEmitter {
  constructor() {
    this.events = {};
  }
 
  // Implement the on/emit/off methods
}
Other Extensions