「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
前言
最开始学编程的时候,老师讲,闭包,这个东西大家要重视。
当时觉得,害,无非就是能够调用别的方法内部变量的方法,可以将参数包裹起来,一看见我就认识,自己还能写出来!
最近遇见了一系列的面试题,哎嗨,深入研究一下。
题库如下:
-
什么是闭包?
-
闭包的作用
-
闭包与柯里化、偏应用函数的关系
-
谈谈闭包域即时函数的应用
-
如何利用闭包完成类库封装
-
如何用闭包完成模块化(Webpack原理)
从第一个开始:
闭包是什么
这道题直接讲概念就是:有权访问另一个函数作用域中的变量的函数,就是闭包。
我们常见的创建方式就是
function animal() {
const name = "lulu";
function catName() {
console.log(name);
}
catName();
}
animal();
好了,问题来了,在JS中
const name = "kitty"
function catName () {
console.log(name);
}
这个是闭包么???
答案是,,是!
为什么?
我们的name定义在全局作用域中,catName在内部输出找不到自己定义的值,因此向外寻找,输出name,是一个隐性的闭包;
但是正常我们工作学习中都会采用方法一来进行封装,最主要的优点就是隐藏变量、避免全局污染
由于js的垃圾回收是基于标记清除
(挖坑),而闭包中的变量会通过作用域链作用而被长期的在内存调用中占用,因此闭包使用过多会有一个非常明显的弊端变量不会被垃圾机制回收,造成内存泄漏
。
什么是作用域链呢?
当某个函数被调用时,会创建一个执行环境(execution context)及相应的作用域链。使用arguments和其他命名参数的值来初始化函数活动对象(activation object)。但在作用域链中,外部函数的活动对象始终层层递增,一直到作用域链终点的全局执行环境。
函数执行时,为读取和写入变量的值就需要层层不断向上查找。后台的每个执行环境都有一个变量对象,全局变量对象将在环境中始终存在。
对于当前函数的执行环境,每个作用域链中都会包含:本地活动对象和全局变量对象。
当我们在函数中访问一个变量的时候,就会从作用域链中搜索具有相应名字的变量。
闭包在初始化的时候,作用域链会被创建,即使内部函数已经不运行,但是引用此函数的作用域链中依然保存着这个函数的活动对象。
直到所有运行都被销毁,最终才会被垃圾回收销毁。
var A = friend() {console.log(a)};
var B = A();
// 这种情况下,我们运行完毕friend变量依然不会被释放,因为还有B在使用
// 因此我们需要强制释放
A = null
因此我们在使用的时候,要小心内存泄漏。
那么,下一个问题来了,闭包有什么用呢?
欲知详情如何,请听下回分解。
末尾指路
这是我JS闭包系列的文章合集