首页 > 科技 > 「JavaScript 从入门到精通」17.闭包

「JavaScript 从入门到精通」17.闭包

前置知识:

声明函数两种方法:

  • 函数声明,存在函数声明提升,因此可以在函数声明之前调用(不会报错)。
  • 函数表达式,不存在函数声明提升,若定义前调用,会报错(函数还不存在)。

1.概念

1.1 词法作用域

这里先要了解一个概念,词法作用域:它是静态的作用域,是书写变量和块作用域的作用域。

由于函数g的作用域中没有a这个变量,但是它可以访问父作用域,并使用父作用域下的变量a,最后输出"leo"。

词法作用域中使用的域,是变量在代码中声明的位置所决定的。嵌套的函数可以访问在其外部声明的变量。

1.2 闭包

接下来介绍下闭包概念,闭包是指有权访问另一个函数作用域中的变量的函数。

闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。

创建闭包的常见方式:在一个函数内创建另一个函数。如:

通过概念可以看出,闭包有以下三个特征:

  • 函数嵌套函数
  • 函数内部可以引用函数外部的参数和变量
  • 参数和变量不会被垃圾回收机制回收

注:关于内存回收机制,可以查看阮一峰老师的《JavaScript 内存泄漏教程》。

另外,使用闭包有以下好处:

  • 将一个变量长期保存在内存中
  • 避免全局变量的污染

因为垃圾回收机制没有回收,所以每次调用fun()都会返回新的值。

  • 私有化成员,使得外部不能访问

2.易错点

2.1 引用的变量发生变化

原本照我们的想法,fun方法中每个元素上的方法执行的结果应该是1,2,3,...,10,而实际上,每个返回都是10,因为每个闭包函数引用的变量i是f执行环境下的变量i,循环结束后,i已经变成10,所以都会返回10。

解决办法可以这样:

2.2 this指向问题

由于里面的闭包函数是在window作用域下执行,因此this指向window。

2.3 内存泄漏

当我们在闭包内引用父作用域的变量,会使得变量无法被回收。

这样做的话,变量a会一直存在无法释放,类似的变量越来越多的话,很容易引起内存泄漏。我们可以这么解决:

通过把变量赋值成null来主动释放掉。

3.案例

3.1 经典案例——定时器和闭包

代码如下:

不出所料,返回的不是我们想要的0,1,2,3,...,9,而是10个10。

这是因为js是单进程,所以在执行for循环的时候定时器setTimeout被安排到任务队列中排队等候执行,而在等待过程中,for循环已经在执行,等到setTimeout要执行的时候,for循环已经执行完成,i的值就是10,所以就打印了10个10。

解决方法 :

  • 1.使用ES6新增的let。

把for循环中的var替换成let。

  • 2.使用闭包

3.2 使用闭包解决递归调用问题

因为最好是return num* arguments.callee(num-1),arguments.callee指向当前执行函数,但是在严格模式下不能使用该属性也会报错,所以借助闭包来实现

这里可以使用return num >1 ? num* arguments.callee(num-1) : 1;,因为arguments.callee指向当前执行函数,但是在严格模式下不能使用,也会报错,所以这里需要使用闭包来实现。

这样做,实际上起作用的是闭包函数f,而不是外面的fun。

3.3 使用闭包模仿块级作用域

ES6之前,使用var声明变量会有变量提升问题:

为了避免这个问题,我们这样使用闭包(匿名自执行函数):

我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在函数执行完后会立刻释放资源,关键是不污染全局对象。这里i随着闭包函数的结束,执行环境销毁,变量回收。

但是现在,我们用的更多的是ES6规范的let和const来声明。

公众号:前端自习课

往期回顾

「JavaScript 从入门到精通」1.语法和数据类型

「JavaScript 从入门到精通」2.流程控制和错误处理

「JavaScript 从入门到精通」3.循环和迭代

「JavaScript 从入门到精通」4.函数

「JavaScript 从入门到精通」5.表达式和运算符

「JavaScript 从入门到精通」6.数字

「JavaScript 从入门到精通」7.时间对象

「JavaScript 从入门到精通」8.字符串

「JavaScript 从入门到精通」9.正则表达式

「JavaScript 从入门到精通」10.数组

「JavaScript 从入门到精通」11.Map和Set对象

「JavaScript 从入门到精通」12.使用对象

「JavaScript 从入门到精通」13.迭代器和生成器

「JavaScript 从入门到精通」14.元编程

「JavaScript 从入门到精通」15.JS对象介绍

「JavaScript 从入门到精通」16.JSON对象介绍

本文来自投稿,不代表本人立场,如若转载,请注明出处:http://www.souzhinan.com/kj/246894.html