留言与评论(共有 0 条评论) |
发布时间:2020-04-12 08:37:03
网上对闭包的解释都太专业了!我给个「非专业」的解释!有不对的地方,还望指正!
编程的本质是什么?是抽象+组合:
面向过程编程将业务抽象为数据结构+方法(过程),通过方法的组合来解决问题
面向对象编程将业务抽象为一个个的对象,通过对象间的组合通信来解决问题
函数式编程将业务抽象为一个个的函数,通过函数间的组合来解决问题
但是每种抽象方式都不是万能的。都是擅长某些方面,而不太擅长某些方面(否则就不会有越来越多的语言支持多种编程范式了。)而大部分的语言特性就是用来弥补自身不擅长的地方。比如闭包。
「闭包」的作用就是为了「实例化」函数!「实例化」的目的是为了保持状态!
我们来看一个OO的例子,我有一个类:
class Calc{
private int num;
public Calc(int num){
this.num
= num;
}
public int calc(int x) {
return x + num;
}
}
通过这个类,我就能实例化出来多个不同状态的对象:
addOne = new Calc(1);
addTwo = new Cacl(2);
addOne.calc(1); // 2
addTwo.calc(2); // 3
你可能会说,这在js里还不简单,定义个函数就可以了啊。
function add(a,b) {
return a + b;
}
add(1,1);
add(1,2);
假设有1w个地方需要调用这个函数,你需要多写1w个1或2。后期如果要把1或2改成3的话,需要改1w个地方。上面的面向对象只需要在实例化的时候修改一下就可以了。
如果使用闭包呢?
function calc(num){
return function(a){ return a + num;}
}
addOne = calc(1);
addTwo = calc(2);
addOne(1); // 2
addTwo(2); // 3
是不是和上面的先定义了类,再实例化是一样的了?如果需要调整1或者2为3,只需要在构建闭包的时候调整一下就可以了。
最后再解释一下,为什么叫闭包呢?看上面的匿名函数!这个函数需要一个外部的变量num。当传递了num给它之后,它就不再需要直接访问外部的值了(只通过传入参数的方式获取值)。换种说法就是它对外关闭了!所以称为「闭包」!
我是一名前端,无意间看见这个问题,我来回答一下!
我曾经写过一篇博客用来介绍闭包,谈不上通俗易懂,但是可以理解的比较深入!我个人认为理解闭包的概念的前提是理解作用域以及js的垃圾回收机制!
定义
作用域:变量和函数的可访问范围!
闭包:在某个作用域内定义的函数,它可以访问这个作用域内的所有变量!
从定义上看,我觉得闭包是函数作用域中一种现象,而且在es6之前,js只有函数级作用域,没有块级作用域,那么我们就来看看函数级作用域的特点!
函数级作用域
[[scope]]是所有父变量对象的层级链,处于当前函数上下文之上,在函数创建时存于其中。
全局上下文的变量对象是:
在getIdFac创建时,它的[[scope]]属性是:
在getIdFac执行时,其上下文的活动对象是:
getIdFac上下文的作用域链为:
内部函数cac创建时,其[[scope]]为:
在cac执行时,其上下文的活动对象为:
cac上下文的作用域链为:
内存管理
由于cac在包含它的函数外执行,对全局作用域中的变量x 和 父函数中y存在这个引用,所以呢,x和y所占的存储空间不会被回收!
综上,闭包存在于函数中,它是作用域的一种现象!
喜欢我的回答就关注我吧,有问题可以发表评论,我们一起学习,共同成长!
简单通俗易懂的讲就是一个函数里面还有一个函数,然后这个内部函数里用到了外部函数的变量,这个内部函数就叫闭包。
概念通俗易懂,不过也得注意其用途。
它的最大用处有两个,一个是前面提到可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
简单解释下这两句话,我们在外部是无法访问到函数内部的变量的,如果我们想要访问,则可以通过在内部创建一个函数,也就是闭包来访问这个函数,然后通过外部函数返回这个闭包,那我们在外部就可以通过这个闭包来访问这个函数的内部变量了。
接着上面的情况,如果这个闭包我们赋值在一个全局变量上,那么这个闭包就保存在内存中,由于闭包访问了它外部函数的变量,所以又依赖于它的外部函数,这个外部函数也就保存在内存中,不会再调用结束后被垃圾回收机制回收。
写一个最简单的闭包函数:
<script>
function fn1(){
var x = 10;
function fn2(){
alert(x);
}
return fn2; // 返回fn2的地址
}
var fn = fn1(); // 相当于fn指向了fn2的地址
fn(); // 执行fn2函数
</script>
解释:执行完var fn = fn1()的时候,fn1()会函数调用,去执行fn1的函数体,执行完毕之后,就会把fn1函数对象里的内部函数fn2函数对象的地址返回,按道理来说,fn1函数里面的局部变量x应该要被释放才对,但是由于fn2函数里面alert(x)用到了局部变量x,那么这个时候js引擎就不能把fn1函数对象进行垃圾回收,因为如果fn1函数对象被垃圾回收了,也就是意味着x变量就释放了,那么fn2函数对象里面还怎么能使用到x变量呢?而var fn = fn1(),其实就相当于fn变量指向了fn2函数对象的地址,既然是函数地址,那么就可以fn()函数调用,而fn2函数对象是在fn1函数内部,就说明fn1函数对象并不能被垃圾回收,这样也就是说外部可以访问一个函数内部的局部变量了。
闭包的作用:
1、可以访问一个函数的内部的变量
2、使此局部变量所占用的内存不被释放。
最简单的理解,子程序里的子程序
留言与评论(共有 0 条评论) |
全站搜索