面试必问——闭包

面试中经常被问到闭包的理解,总是回答的不够好,不能完全理解,现在这边做个总结

闭包的基础知识

理解闭包之前必须要理解的变量作用连

  • JavaScript变量有两种:全局变量,局部变量
  • 局部变量作用域一般在函数里面,在函数之外的视为全局变量
  • 一般来说,在函数里面可以访问全局的变量,在函数外面不可以访问函数里面的变量
  • Javascript存在“链式作用域”结构(chain scope),这里的链式作用域可以理解为函数嵌套,子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立.
什么是闭包

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见方式,就是在一个函数内部创建另一个函数。之所以一个内部的函数可以访问其外部的变量,而且在其被返回或是调用时还可以访问,是因为这个内部函数的作用域链中包含外部函数的作用域。

闭包的优点和缺点

闭包对新手是比较难易理解的,不是非必要环境不要使用,使用完了一定要清除闭包

优点

  • 实现了可以访问其他作用域变量,并且避免了全局变量对自身词法作用域变量的污染
  • 可以把局部变量(自身作用域的变量)驻留在内存中一直保存着上一次执行的值,不会被垃圾回收机制回收,从而避免使用全局变量

缺点

  • 局部变量一直驻留在内存中不会被回收,导致内存被爆满,影响程序性能
闭包的常见形式

形式一:

function fun1(){
    return function(){
        //闭包主体
    }
}
var res=fun1();
res();//闭包函数调用

形式二:

(function(i){   
	//闭包主体
})(i);//闭包函数自调用
闭包的应用

闭包在日常开发中有哪些地方可以使用呢,这里做了几个经典场景

几个 li 中 点击当前 li 返回当前的下标

<ul>
     <li>1</li>
     <li>2</li>
     <li>3</li>
     <li>4</li>
 </ul>

新手如果稍加不注意就会写成

var li = document.querySelectorAll('li');
for(var i=0;i<li.length;i++){
    li[i].onclick = function(){
        console.log(i)
    }
}

这时候点击都返回的是4,因为for循环的i定义的是全局变量,里面的方法的i是向上寻找,就返回全局变量的i,最后点击的时候i已经变成了4

解决办法
for(var i=0;i<li.length;i++){
    (function(i){
        li[i].onclick = function(){
            console.log(i)
        }
    })(i) 
}

在循环的时候把i传到闭包里,变成了一个局部变量,使用闭包来实现

防抖和节流,也可以利用闭包的原理,来解决开发中的一些问题。

防抖

函数防抖(debounce):就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

var debounce= function(fn,interval){
    let _fn = fn,
    timer;
    return function (...args){
        if(timer){
            clearTimeout(timer);
            timer = null;
        }
        timer = setTimeout(function(){
            clearTimeout(timer);
            timer = null;
            _fn.bind(this)(...args)
            
        },interval||500)
    }
}

函数节流(throttle):所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。

var throttle = function(fn,interval){
    let _fn = fn,
    timer,
    onefn =true;    //是否是第一次  如果不需要可以去掉
    return function (...args){
        if(onefn){
        	//第一次直接执行
            _fn.bind(this)(...args)
            return onefn=false;
        }
        if(timer){
            return false;
        }
        timer = setTimeout(function(){
            clearTimeout(timer);
            timer = null;
            _fn.bind(this)(...args)
        },interval||500)
    }
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值