JS 函数相关

JS 闭包

在 JavaScript 中,闭包(Closure)是常见的概念之一。它可以用来创建独立的变量空间,保护变量,同时也能为编写高级函数提供支持。下面我们来详细学习一下什么是闭包以及它的应用。

什么是 JS 闭包?

简而言之,闭包就是一个函数中包含了另一个函数,并且内部函数可以访问外部函数的变量,即使外部函数已经执行完毕。这种情况下,内部函数所使用到的外部变量将被保存在内存中,不会被垃圾回收器回收,这就是闭包。

实现 JS 闭包

下面是一个简单的示例代码,展示了如何创建闭包:

1
2
3
4
5
6
7
8
9
10
11
12
function outerFunc() {
const name = "John";

function innerFunc() {
console.log(`Hello, ${name}!`);
}

return innerFunc;
}

const result = outerFunc();
result(); // 输出:Hello, John!

在这个示例中,outerFunc 是一个外部函数,返回的是内部函数 innerFunc 的引用。由于 innerFunc 可以访问 outerFunc 中的 name 变量,因此当 outerFunc 执行完成后,name 这个变量并没有被销毁,因为 innerFunc 继续引用它。所以当我们调用 result() 时,输出的就是 Hello, John!

闭包的应用

下面是几个常见的使用场景:

  • 封装变量:在函数中通过闭包来创建私有属性和方法,这样就不会因为外部对内部属性的操作而影响到其他代码的执行。
  • 模块化开发:利用闭包可以将一个模块所需要的所有代码封装在一个函数中,从而避免变量污染和命名冲突的问题。
  • 实现高级函数:JavaScript 中高阶函数可以使用闭包来实现,比如控制函数的执行次数、延迟执行等功能。
  • 缓存变量值:通过闭包可以缓存之前已经计算过的结果,避免重复计算,提高运行效率。

闭包是 JavaScript 中的一个重要概念,可以用来增强代码的可重用性、可维护性和可扩展性。但要注意,如果滥用闭包会导致内存泄漏等问题,因此在使用闭包时需要谨慎。

JS 高阶函数

在 JavaScript 中,高阶函数是指能够接受函数作为参数或返回一个函数作为结果的函数。这种函数可以让代码更简洁、模块化和可复用。

以下是一些常见的高阶函数:

  1. map:将一个数组映射成另一个数组,映射规则由传入的函数决定。
1
2
3
4
5
const arr = [1, 2, 3];
const newArr = arr.map(function (item) {
return item * 2;
});
console.log(newArr); // 输出:[2, 4, 6]
  1. filter:过滤掉符合条件的元素,留下不符合条件的元素。
1
2
3
4
5
const arr = [1, 2, 3, 4, 5, 6];
const newArr = arr.filter(function (item) {
return item % 2 === 0;
});
console.log(newArr); // 输出:[2, 4, 6]
  1. reduce:对数组中的元素依次执行回调函数,最终返回一个累计值。
1
2
3
4
5
const arr = [1, 2, 3];
const sum = arr.reduce(function (prev, curr) {
return prev + curr;
}, 0);
console.log(sum); // 输出:6
  1. sort:对数组进行排序,排序规则由传入的函数决定。
1
2
3
4
5
const arr = [3, 2, 1];
arr.sort(function (a, b) {
return a - b;
});
console.log(arr); // 输出:[1, 2, 3]

高阶函数是 JavaScript 中非常重要的概念之一,它可以让代码更加简洁、模块化和可复用。通过灵活使用高阶函数,我们可以使代码更加优雅,并且提高开发效率。

柯里化

柯里化(Currying)是一个函数式编程的概念,指的是将一个接受多个参数的函数转换成一系列只接受单一参数的函数,并返回一个新的函数。这样做可以使函数更加灵活、模块化,并方便组合使用。

下面是一个简单的例子,展示了如何实现柯里化:

1
2
3
4
5
6
7
8
9
function add(a) {
return function (b) {
return a + b;
};
}

const increment = add(1); // 定义增量函数
const result = increment(5); // 调用增量函数
console.log(result); // 输出:6

在这个例子中,add 函数接收一个参数 a 并返回一个内部函数,该函数接收一个参数 b 并将 ab 相加。当我们用 add 函数传入一个参数 a 后,得到的就是一个新函数,这个新函数接收一个参数 b 并返回最终结果。结果是一个具有记忆性的纯函数,因此它非常适合用于函数式编程。

下面再来看一个稍微复杂一些的例子,它展示了如何将柯里化应用于多参函数的场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function multiply(a, b, c) {
return a * b * c;
}

function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(null, args);
} else {
return function (...rest) {
return curried.apply(null, args.concat(rest));
};
}
};
}

const curriedMultiply = curry(multiply); // 将函数柯里化

console.log(curriedMultiply(2)(3)(4)); // 输出:24
console.log(curriedMultiply(2, 3)(4)); // 输出:24
console.log(curriedMultiply(2)(3, 4)); // 输出:24

在这个例子中,curry 函数接收一个多参数函数 fn 并返回一个新函数 curried。当使用 curried 函数传入参数时,如果参数数量已经足够,则直接调用 fn 函数并返回结果;否则继续返回一个新函数,并将已经传入的参数以 concat 方式拼接到新参数列表中。

柯里化是函数式编程中非常重要的概念之一,在 JavaScript 中也是非常实用的技能。通过柯里化可以使函数更加灵活、模块化,并方便组合使用。