Advance JavaScript - Function
Tags: javascript, beginners, webdev, programming
Published: 2024-01-23 08:02:24

Generally speaking, a function is a "subroutine" that can be called by external code (or internally through recursion). Similar to a program itself, a function consists of a series of statements called the function body. Values can be passed to a function, and the function will return a value. In JavaScript, functions are considered first-class objects because they can have properties and methods just like any other object. The difference is that functions can be invoked. This article primarily covers some practical techniques for using functions in JavaScript, intending to help developers enhance their skills during the development process.

### IIFE
```js
(function () {
  statements;
})();
```
To achieve immediate execution, you can wrap a function with parentheses outside the function body and then invoke it with parentheses. However, the contents inside this function cannot be accessed from outside unless they are attached to an existing object.

![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b7819fa0cf0447b29d9731f31466264e~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=926&h=410&s=61282&e=png&a=1&b=1c1d20)

When working on a project without using a framework and writing pure JavaScript, this approach of using immediately invoked functions can be used to isolate variables and achieve variable scoping. By encapsulating code within the function, variables declared inside the function are not accessible from outside, providing a form of variable isolation. If data needs to be shared between different parts of the code, a common object can be used to pass the data between functions or modules.

### arguments
Inside a function, you can access the data of the received arguments. The arguments object can only be used within the function.
```js
function A() {
  console.log(arguments)
}

A(1,2,3, [1,2,3]);
/*
{
  "0": 1,
  "1": 2,
  "2": 3,
  "3": [
    1,
    2,
    3
  ]
}
*/
```
The arguments object is an object that behaves like an array-like object. It is a collection of the arguments passed to a function. However, it is not a true array and does not have access to array methods directly. To perform array operations on the arguments object, you need to convert it into a proper array using the Array.from(arguments) method or by spreading it into an array [...arguments]. This conversion allows you to use array methods and perform various array operations on the arguments.

![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4135eb4820db4884ae4a3b0a7e6d3335~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=709&h=214&s=28409&e=png&a=1&b=1b1c1f)
### Function.length
You can retrieve the number of parameters inside the parentheses of a function. If there are default parameters defined, the count will represent the number of parameters before the default parameters are accounted for.

![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4c37adb1dfb1415bb815aac97acf9313~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=548&h=218&s=26207&e=png&a=1&b=1b1c1f)

### closure
A closure is a combination of a function and the lexical environment (the surrounding state) in which the function was declared. In other words, closures allow developers to access the scope of an outer function from an inner function. In JavaScript, closures are created simultaneously with the creation of a function.

We can utilize the characteristics of closures to perform certain timer operations:
#### 1. debounce
```js
const debounce = (fn, during) => {
    const timer = null;
    return (...args) => {
        clearTimeout(timer); 
        timer = setTimeout(() => { fn(...args) }, during);
    }
}
```
#### 2. throttle
```js
const throttle = (fn, during) => {
    const timer = null;
    return (...args) => {
        if (!timer) {
            timer = setTimeout(() => {
                fn(...args);
                clearTimeout(timer);
                timer = null;
            }, during);
        }
    }
}
```
### Recursion
Recursion is a process in which a function calls itself. It is a technique where a function solves a problem by breaking it down into smaller, similar subproblems. In recursion, the function continues to call itself with different inputs until a base condition is met, which stops the recursive calls. This allows the function to solve complex problems by solving simpler versions of the same problem repeatedly. Recursion can be a powerful tool in solving problems that exhibit repetitive or self-referential structures.

```js
let x = 0;
// “x < 10” 
while (x < 10) {
  // do something
  x++;
}

function loop(x) {
  // “x >= 10” 
  if (x >= 10) {
    return;
  }
  // do something
  loop(x + 1); // Recursion
}
loop(0);
```

Fibonacci sequence

```js
function fib(n) {
    if (n === 1 || n === 2) return n;
    return fib(n - 1) + fib(n - 2)
}
```
### Currying
Using recursion, it is also possible to achieve currying. Currying is a function transformation technique that converts a callable function f(a, b, c) into a callable form f(a)(b)(c).
Currying does not invoke the function directly. It is merely a function transformation technique that converts a function into a curried form without actually executing it.

When a function is curried, it returns a new function for each partial application of its arguments. These returned functions can be invoked later with the remaining arguments to produce the final result. Currying enables the creation of more specialized and reusable functions by breaking down a function with multiple arguments into a series of functions with single arguments.

In essence, currying transforms the way a function is called, allowing for more flexible and modular usage, but it does not trigger the execution of the original function until all the necessary arguments have been provided.

```js
const curry = fn => 
    curried = (...args) => 
        (...arg) => {
            // Recursion
            if (arg.length === 0) {
                return fn(...args, ...arg)
            } else {
                return curried(...args, ...arg)
            }
        }
    const sum = (...args) => {
        return args.reduce((a,b) => a+b, 0);
    }

const curriedSum = curry(sum);
console.log('curry test',curriedSum(1)(1,3)(3,3,3,3,3,3)())

// "curry test" 23
```