JS闭包
闭包是什么?为什么需要闭包
闭包就是能够读取其他函数内部变量的函数,在本质上,闭包是将函数内部和函数外部连接起来的桥梁
对百度得来的这句话进行逐字分析
1、能够获取其它函数内部变量?
我们都知道,js中,局部变量在全局是无法直接访问到的,如下
function f1(){
var name = 'f1'
}
console.log(name);
相信大家都知道这里name并不是f1。
2、闭包能够读取其它函数内部变量
如何读取?
3、闭包是个函数?
头大,分析到这里还是不明白,但我们似乎还是难以理解什么是闭包。
那我们还可以再掌握一些前提
变量的生命周期
- 全局变量:页面关闭,结束生命周期
- 局部变量,在函数执行完毕或者销毁,结束生命周期
为什么需要闭包?
闭包可以调用函数内部的变量,从而避免大量外部声明导致的变量污染
闭包的原理
当一个函数执行完毕后,正常情况下这个函数内部的变量会被销毁。但是如果存在其它函数引用这些变量,则这些变量不会被销毁,一直被引用,没有被销毁。
读到这里,则对闭包会有初步的了解。直接上代码分析,如下代码所示:
function f1(){
var count = 1
function f2(){
count ++
console.log(count);
}
return f2
}
let t = f1() //f1()执行的结果就是闭包,因为f1返回了一个函数(f2)
t()
//闭包形成的条件,返回的是一个函数,并且这个函数对局部变量存在引用,维持变量的存在
//因为变量a被f2引用了,所以a不会被销毁,而是被维持着
闭包是一个函数,因此相互直接不会有影响,每个都是私有的。
function f1(){
var count = 1
function f2(){
count ++
console.log(count);
}
return f2
}
let t = f1()
t() //2
t() //3
t() //4
let t2 = f1()
t2() //2
let t3 = f1()
t3() //2
t3() //3
可以见到,这个count并不是2、3、4、5、6、7这样加下去,而是每个实例都是从头开始加,这也证明了闭包之间是互不影响的。
举例说明下闭包的应用
vue中的应用。在最初学习vue时,我们的data都是直接用大括号的,因为我们只是单一组件用它,并不会涉及多个组件同时用这个data。 但是随着后面逻辑越来越复杂,我们会创建多个组件,那么这种大括号形式,数据是不隔绝的(原因是引用地址问题),因此不同组件数据是会有影响的。举个例子
const MyComponent = function() {};
MyComponent.prototype.data = {
a: 1,
b: 2,
}
const component1 = new MyComponent();
const component2 = new MyComponent();
component1.data.a === component2.data.a; // true;
component1.data.b = 5;
component2.data.b // 5
这里可以看到,这里的data就是引用数据类型,当修改了component1.data.b时,component2.data.b也会变化。因此,我们的data就变成了如下这种格式,变成了一个函数,这就是一个闭包的应用。
data(){
return{
name:'',
...
}
}
实战中闭包具体应用场景
数据的交互,比如封装一个ajax
为什么不选择直接返回一个function,而是选择返回一个对象,主要原因是为了预留空间,更好的扩展。
function f1(){
let xmlhttp = new XMLHttpRequest()
return function(){
}
}
//采用如下方式
function f1(){
let xmlhttp = new XMLHttpRequest()
return {
request:function(){
}
}
}
function Http(){
let xmlhttp = new XMLHttpRequest()
let _url = ''
return {
request:function(method,url,data,success,error){
xmlhttp.open(method,_url + url)
if(method == 'get'){
xmlhttp.send()
}else{
xmlhttp.setRequestHeader("Content-Type","application/json")//请求投
xmlhttp.send(data)
};
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
success(xmlhttp.responseText)
}
}
}
}
}
闭包的缺点
- 不必要的闭包只会徒增内存消耗。
- 如果引用闭包的函数是一个全局变量,那么闭包会一直存在直到页面关闭;但如果这个闭包以后不再使用的话,就会造成内存泄漏。
使用原则
- 如果闭包一直使用,则可将其置为全局变量
- 如果使用频率低,则做为局部变量