javascript闭包


highlight: agate

一、函数的使用

1、函数作为参数

```javascript // 将函数作为另一个函数的参数 function foo(fn){ fn() } function bar(){ console.log("将函数作为另一个函数的参数") } foo(bar)

function calc(num1, num2, calcfn){ console.log(calcfn(num1,num2)) } function add(num1, num2){ return num1 + num2 } function sub(num1, num2){ return num1 - num2 }

let num1 = 10, num2 = 20; calc(num1,num2,sub) ```

2、函数作为返回值

1)简单的案例

```javascript function foo(){ function bar(){ console.log("函数作为返回值") } // 返回bar函数 return bar }

const fn = foo() fn() // 这个其实是在指执行bar函数 ```

2)参数相加

```javascript /** * 按理说,下面的fun执行结束,count就会销毁,但是因为闭包的原因,导致他不会进行销毁 */ function fun(count){ return function add(num){ return count + num } }

const fn2 = fun(3) console.log(fn2(9)) // 12 console.log(fn2(11)) // 14 ```

3、函数和方法的具体区别

函数:独立的function,称之为是一个函数

方法:当我们的一个函数属于某一个对象时,我们称这个函数为这个对象的方法

4、数组中的函数

1)filter的使用

javascript let arr = [11,22,55,44,66] /** * filter() 过滤的使用(他是方法) * 他的返回值是个布尔值,同时也会返回一个 数组 * filter()的参数是个函数,该函数的参数如下: * item 每个元素 * index 每个元素的下标 * Array 传入的整个数组 */ const newArr = arr.filter(function (item, index, Array) { if(item % 2 === 0){ return true } }) console.log(newArr) // [ 22, 44, 66 ]

2)map 映射

javascript let arr = [11,22,55,44,66] /** * map 映射 * 他有返回值 */ let newArr = arr.map(function (item, index){ return item + 1 }) console.log(newArr)

3)forEach 迭代

javascript let arr = [11,22,55,44,66] arr.forEach(function (item, index){ console.log(item,index) })

4)find 查找元素

javascript let arr = [11,22,55,44,66] /** * find 查找 * 他的返回值时布尔值 * 他会返回一个元素 */ let newArr = arr.find(function (item){ if (item === 22) return item }) console.log(newArr)

5)findIndex 查找对象所对的索引值

javascript let arr = [ 11, 22, 55, 44, 66 ] const findIndex = arr.findIndex(function (item){ if (item === 22) return true }) console.log(findIndex)

6)reduce 累加

```javascript let arr = [ 11, 22, 55, 44, 66 ] /** * reduce 累加 * 他的参数是个函数 和 初始值 * 该函数的参数 如下: * preValue 上一次的返回值 * item 当前值 * 初始值 可以按照需求传入,默认不穿的时候为0 */

let newArr4 = arr.reduce(function (preValue, item){ // 返回一个10,就代表他的第二次来的时候preValue就为十了 // return 10 return preValue + item }, 0) console.log(newArr4) // 198 ```

二、JS闭包

1、闭包的初步认识

1)闭包是指有权访问另一个函数作用域中的变量的函数(也就是能够读取其他函数内部变量的函数)

2)作用:函数内部的变量,只能在当前函数内部使用,而你要在函数外部使用函数内部的变量,这个时候,你就要使用闭包来完成

文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

javascript function makeFunc() { let name = "你好" function displayName() { console.log(name) } return displayName } /** * 在makeFunc()执行完之后,按理说 它里面的内容是要销毁的(也就是 name 本来是要销毁的) * 但是在执行displayName这个函数的时候,你依然可以访问到本来要销毁的变量时,依然可以访问到 * 在下面调用(displayName)的时候,依然可以访问到makeFunc函数里面的变量,这个时候,他就形成了闭包 * 闭包的组成:函数 + 可以访问的自由变量 */ let myFunc = makeFunc() //myFunc就是displayName这个函数 myFunc();

2、闭包的定义

① 闭包跟函数最大的区别在于,当捕捉闭包的时候,它的 自由变量 会在补充时被确定,这样即使脱离了捕捉时的上下文,它也能照常运行;

② 闭包在实现上是一个结构体(整体),它存储了一个函数和一个关联的环境(相当于一个符号查找表);

③ 闭包是由两个东西组成,一个可以用来返回的函数,一个外层的自由变量,只有能在返回的这个函数里,访问到外层的这个自由变量,这两个东西结合在一起,就组成了严格意义上的闭包;

javascript function foo(){ let name = "哈哈哈" let age = 18 function bar (){ console.log(name) console.log(age) } return bar } /** * 1、按理说上面的bar函数是要销毁的,但是在执行的时候,你给了他一个return * 2、这个时候,你在下面定义全局变量的时候,就把他赋值给fn了,这个时候,他就不会被销毁了 */ let fn = foo() fn()

三、闭包的内存泄露

image-20220205001011667

1、闭包内存泄露的描述

:因为有一个父级作用域一直指着,所以才不会销毁,也就是在一个函数里你return了一个函数,但是你在外面又去调用外层函数的时候,这个时候,他会把return里面的那个函数进行赋值,从而导致内存不会进行销毁

2、解决内存泄露的方式

把定义的函数,置为null

3、闭包内存泄露案例

```javascript function fun(){ /** * 传入一个长度 * 后面使用fill作为填充,填充的内容时1 * 一个整数是4个字节 * 填充1的个数是 1024 * 1024 * @type {any[]} */ let arr1 = new Array(1024 * 1034).fill(1) return function (){ console.log(arr1.length) } }

// const arrFn = fun() // arrFn()

let arr2 = [] for (let i = 0; i < 100; i++){ /** * 必须要有一个引用接收,负责他会销毁 * 这里面有100 函数对象 */ arr2.push(fun()) } // 下面是销毁(但是他不是立马销毁的) arr2 = null ```

image-20220220205558101 alt="闭包内存回收和this的四个绑定规则(1)"

4、闭包中自由变量是怎么销毁的

​ 根据ECMA规范得到,在闭包的父级作用域的自由变量都是保存的,但是js引擎,会帮我们进行优化处理,在定义后的代码里面,如果后面没有指向的话,他在执行的时候,就会帮我们把这个未使用的自由变量销毁掉。

```javascript // 请把他引入html中运行 function fun(){ let name = "哈哈哈", age = 22 function bar() { debugger console.log(name) } return bar }

const fn = fun() fn() ```

image-20220222235404686

四、闭包的使用

1、闭包实现柯里化

具体的参考阮一峰的函数式编程入门教程:https://www.ruanyifeng.com/blog/2017/02/fp-tutorial.html

```javascript // 柯里化之前 function add(x, y) { return x + y; }

console.log(add(1, 2)); // add(1, 2) // 3

// 柯里化之后 function addX(y) { return function (x) { return x + y; }; }

console.log(addX(2)(1)); addX(2)(1) // 3 ```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值