闭包的使用场景和闭包内存释放

闭包的使用场景和闭包内存释放,第1张

什么是闭包:
简单来说,闭包就是定义在一个函数内部的函数(函数的嵌套),内部函数可以访问外层函数的内部变量,外部函数return 内部函数。外部函数被其它外部调用。如下代码

function bibao(){
		var a=0;
		function bibaoInner(b){
				alert(a+b)
		}
		return bibaoInner;
}
function bibaoAction(){
		var c=bibao();
		console.log(c(5));
}
bibaoAction();

「函数」和「函数内部能访问到的局部变量」,就是一个闭包。这里局部变量a 和函数bibaoInner就形成了闭包;又如下面代码

function bibao(c) {
	var a = 0;
	var pp = function bibaoInner(b) {
		return a + c + b;
	}
	return pp;
},
bibao(2)(3);

return pp,是为了外面可以访问这个闭包。与闭包本身无关。
闭包如此简单,那闭包有什么特性?

全局变量不会被回收,局部变量在函数执行完成以后,函数内部的东西就会被销毁,除非被被另一个作用域所引用就不会被回收。看上面代码:bibao函数,a为局部变量,bibao(2)(3)执行,实际就是对bibao内部函数pp的执行,pp执行会引用到bibao中的a 。所以a不会被回收。
所以闭包占用内存,不易被释放。如下面代码:

    function fun(){
        var i=0;
        return function(){
            alert(i++);
        }
    }
    fun();//返回一个函数
    fun()();//d出0
    fun()();//d出0
    var f1=fun(),f2=fun();
    f1();//d出0
    f1();//d出1
    f1();//d出2
    f2();//d出0

再次调用f1(),也就是还在引用f1中i的变量,经过第一次调用f1,i++已经变成i=1;所以再次调用f1,会输出1 。
然后再调用f2(),按理说应该是2了。但不是,答案是0 。因为调用f2(),就相当于重新调用fun()()。而每一次调用fun(),变量i都会被重新赋值i=0;所以第二次调用f1,输出还是0。

为什么需要闭包?

局部变量无法共享和长久的保存,而全局变量可能造成变量污染。我们希望有一种机制既可以长久的保存变量又不会造成全局污染。所以我们就用到了闭包。当我们不用闭包是,可以将局部变量致空,从而释放内存,如下代码 :

f1=null;
f2=null;

什么情况下使用闭包?
经典例子:

for(var i=1; i<=10,i++){
    setTimeout(function(){
        console.log(i)    
    },1000)
}
//1秒后输出10个11,i是声明在全局作用中的,定时器中的匿名函数也是执行在全局作用域中,所以1秒之后,i的值已经发生了改变,每次都输出11了。

for(var i=1;i<=10;i++){
    (function(j){
        setTimeout(function(){
            console.log(j);        
        },1000);    
    })(i)
}
//
// DOM操作、为元素的伪数组添加事件
let li = document.querySelectorAll('li');
for(var i = 0; i < li.length; i++) {
    (function(i){
        li[i].onclick = function() {
            alert(i);
        }
    })(i)
}

1、闭包的应用比较典型是定义模块,我们将 *** 作函数暴露给外部,而细节隐藏在模块内部

function array() {
	var arr = [];
	this.add = function(val) {
		if (typeof val == 'number') {
			arr.push(val);
		}
	}
	this.get = function(index) {
		if (index < arr.length) {
			return arr[index]
		} else {
			return null;
		}
	}
}
var arr=new array();
arr.add(1);
arr.add(2);
arr.add('xxx');
console.log(arr.get(1));
console.log(arr.get(2));
//arr引用array()
//arr调用相关函数 获取值
//发现arr[]的值没有被销毁,且下次使用的时候,会保留上一次的数据

2、setTimeOut原生第一个函数不能传参数,利用闭包就可以实现传参

function f1(a) {
    function f2() {
        console.log(a);
    }
    return f2;
}
var fun = f1(1);
setTimeout(fun,1000);//一秒之后打印出1

3、封装私有变量

function Animal(value){
    var animal=value;
    var setNum=0;
    this.getName=function(){
        return animal;    
    }
    
    this.setName=function(value){
        setNum++
        animal=value
    }
    this.getNum=function(){
        return setNum    
    }
}
var animal=new Animal("ni")
animal.setName("ho")
console.log(animal.getName())
console.log (animal.getNum())

4、防抖、节流
防抖,代码如下:

export const debounce = (fn, awaits) => {
    let timer;
    return function () {
        console.log("进入防抖");
        let context = this;
        let args = arguments;
        if (timer) {
            clearTimeout(timer);
            timer = null;
        } else {
            timer = setTimeout(function () {
                fn.apply(context, args);
            }, awaits);
        }
    };
};

节流版:

export const throttle = (func, wait) => {
    console.log("进入节流")
    let timeout;
    return function () {
        let context = this;
        let args = arguments;
        if (!timeout) {
            timeout = setTimeout(() => {
                timeout = null;
                func.apply(context, args)
            }, wait)
        }
    }
}

前端学习交流群,永久有效,需要的可以加jjljzh:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1322316.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存