闭包和函数柯里化的理解
1.闭包
当通过调用外部函数返回的内部函数后,即使外部函数已经执行结束了,但是被内部函数引用的外部函数的变量依然会保存在内存中,我们把引用了其他函数作用域变量的函数和这些被引用变量的集合,称为闭包,闭包是这些东西共同的组合。
简单来说,闭包就是指一个函数可以访问另一个函数作用域内的变量。在JavaScript中,每个函数都是一个闭包,因为它们都可以访问自己的作用域内的变量,以及外层函数作用域内的变量。
如何实现闭包?闭包是指一个函数可以访问它定义时所在的词法作用域以及全局作用域中的变量。在JavaScript中,闭包可以通过函数嵌套和变量引用实现。
闭包的理解:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域。(闭包=内层函数+外层函数的变量)
闭包的作用:封闭数据,提供操作,内层的函数访问外层函数的变量
const makeCounter = function () {
let count = 0;
return () => {
count++;
console.log(count);
}
}
let counter = makeCounter();
counter(); // 输出 1
counter(); // 输出 2
counter(); // 输出 3
function a(){
function b(){
var bb = 888
console.log(aa); //输出:666
}
var aa = 666
return b
}
var demo = a()
demo()
在上面的代码示例中,`a`函数定义了一个名为`aa`的变量和一个名为`b`的函数,`b`函数引用了`aa`变量,因此JavaScript引擎会保留`a`函数的作用域链,`b`函数可以访问`a`函数的执行上下文,`b`函数内用到了外部函数`a`的变量`aa`,在`a`函数调用结束后该函数执行上下文会销毁,但会保留一部分留在内存中供`b`函数使用,这就形成了闭包。也就是说:当内部函数引用外部函数的变量时,外部函数的作用域链将被保留在内存中,以便内部函数可以访问这些变量。这种函数嵌套和变量共享的方式就是闭包的核心概念。当一个函数返回另一个函数时,它实际上返回了一个闭包,其中包含了原函数定义时的词法作用域和相关变量。
使用闭包实现数据的私有:
// 以下代码实现了数据的私有,无法直接修改count
function fn(){
let count=1;
function fn1(){
count++;
}
}
// 以下代码中,count是全局变量,很容易被修改
let count = 1;
function fn(){
count++;
}
2.函数柯里化:用于创建已经设置好了一个或多个参数的函数。基本方法是使用一个闭包返回一个函数。
维基百科:柯里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
用大白话来说,就是只传递给函数一部分参数来调用它,让它返回一个新函数去处理剩下的参数。
更通俗的是:
- 输入是一个函数,并且这个函数用于n个参数
- 输出也是一个函数,并且可以用fn()()()这种方式调用
- 参数被柯里化过程中的函数拆分
// 普通函数
const sum = (x, y, z) => {
return x + y + z;
}
// 需求:把上面的函数进行柯里化
const sum1 = x => {
return function (y) {
// 添加业务
return function (z) {
// 添加业务
return x + y + z;
}
}
}
// console.log(sum(1, 2, 3)); // 6
// console.log(sum1(1)(2)(3)); // 6
// 每一个函数都可以取出来,并且可以延迟执行
const fn = sum1(1); // 得到第1个return后的函数
const fn1 = fn(1); // 得到第2个return后的函数
console.log(fn1(1)); // 打印3,1+1+1
函数柯里化等到调用的时候,可以决定要添加的业务——灵活,并且每一个参数可以由和定义方交互之后决定;普通函数、调用的过程中没办法添加业务,降低了调用和定义的互动——并且参数要提前设置好。
函数柯里化的好处:
- 可以把函数式编程变得简洁,没有冗余
- 尽管有多个参数,仍然可以保留数学函数的定义
- 可以将函数作为返回值输出,提前返回