JS中闭包,call的详解以及在防抖节流中的应用

1.什么是闭包

闭包概念:函数内部定义的函数,被返回了出去并在外部调用
形成条件;函数的返回值是函数
优点:实现封装,避免全局变量污染 在适当的时候,可以在内存中维护变量并缓存,提高执行效率。
缺点:函数的变量都保存在内存中,会有内存泄漏问题。在退出函数之前,将不使用的局部变量全部删除。

案例:

let bob=(function(){
    let a=10;
    let b=20;
    function add() {
        return a+b
    }
    function sub() {
        return a-b
    }
    return {
        add,
        sub
    }
})()

let resultAdd=bob.add();
let resultSub=bob.sub();
console.log(resultAdd);		//执行结果为30
console.log(resultSub);		//执行结果为-10

经典面试题:

var data=[];
for(var i=0;i<3;i++){
    data[i]=function(){
        console.log(i);
    };
   
}
data[0]();
data[1]();
data[2]();
//输出 
3
3
3

解释:这里的 i 是全局下的 i,共用一个作用域,当函数被执行的时候这时的 i=3,导致输出的结构都是3
解决办法:1.利用闭包形成的互不干扰的私有作用域
var data=[];
for(var i=0;i<3;i++){
    (
        function(j){
            data[j]=function(){
                console.log(j);
            }
        }       
    )(i)
}
data[0]();
data[1]();
data[2]();
//输出
0
1
2
解决办法:2.利用let,具有块级作用域,形成的私有作用域不干扰
var data = [];

for (let i = 0; i < 3; i++) {
  data[i] = function () {
    console.log(i);
  };
}

data[0]();
data[1]();
data[2]()
//输出
0
1
2

2. call,apply,bind

2.1 call,apply,bind的用法
	let dog={
    name:'旺财',
    sayName(){
        console.log('我是',this.name);
    },
    eat(food,bone){
        console.log('我喜欢吃 ',food,bone);
    }
}
let cat={
    name:'喵喵'
}
dog.sayName.call(cat);		//输出: 我是 喵喵
dog.eat.call(cat,'猫粮','巧克力');	//输出: 我喜欢吃  猫粮 巧克力
//apply,只是传递参数不一样,[arg1,arg2]	
dog.eat.apply(cat,['猫粮','巧克力']);	//输出: 我喜欢吃  猫粮 巧克力

//bind会返回一个函数,单独调用
let fun=dog.eat.bind(cat,'猫粮','巧克力');

fun();	//输出:我喜欢吃  猫粮 巧克力
总结:相似处:都可以改变this指向,使用其他函数的方法
		   不同处:apply的参数是一个数组,bind有返回值
应用:子类可以继承父类的方法
function Animal(){
    this.eat=function(){
        console.log('eat something');
    }
};
function Cat(){
	//this 指向new出来的cat
    Animal.call(this);

}
let cat=new Cat();
cat.eat();		//输出 eat something

3. 防抖与节流

3.1 防抖:一定时间内,频繁触发事件,只执行最后一次(在规定时间内每次触发都要重新计时)

案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body style="height: 1000px;">
    <input type="text">
</body>
<script>
let input=document.querySelector("input");
input.oninput=function(){
	consloe.log(this.value);
</script>
</html>

如果此时输入字符串会出现什么情况?
在这里插入图片描述

它会把每次输入的字符都会发送到后端服务器,造成资源消耗,而我们每次要的只是最后一次的输入值

防抖案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body style="height: 1000px;">
    <input type="text">
</body>
<script>
let input=document.querySelector("input");
input.oninput=debounce(
   function () {
    console.log(this.value);
   },800);
	//封装成一个防抖函数,方便调用
	/**
	 * fn      要执行的业务代码
	 * delay    延时时间,这段时间内就只能执行最后一次的触发事件
	*/
   function debounce(fn,delay){
    
    //当第一次触发,则生成一个t
    //在delay延时时间内再次触发,移除上一个t,并生成新的t
        let t=null;
        return  function(){
        if(t!==null){
            clearTimeout(t);
        }
         t=setTimeout(() => {
             //因为function是被input调用,因此用call可以改变this指向
             //fn的原本指向是window全局对象
                fn.call(this);
            }, delay);
        } 
}
</script>
</html>

在这里插入图片描述
可以看出,通过防抖函数,可以实现与后台服务器的交互大大降低

3.2 节流:一定时间内,频繁触发事件,只执行第一次事件(在规定时间内只执行一次)

案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body style="height: 1000px;">
    <input type="text">
</body>
<script>
window.onscroll=function(){
    console.log('scroll');
}
</script>
</html>

在这里插入图片描述

可以看到,当我们滑动的时候,函数是一直触发的,我们不需要这么高频率的触发。

节流案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body style="height: 1000px;">
    <input type="text">
</body>
<script>
window.onscroll=throttle(function () {
    console.log('hello word');
},800)

/**
 * fn      要执行的业务代码
 * delay    延时时间,这段时间内就只能执行最后一次的触发事件
*/
function throttle(fn,delay) {
    let flag=true;
    return function(){
        if(flag){
        setTimeout(() => {
            //改变this指向,指向引用的对象
            fn.call(this);
            //执行完这次,下一个delay时间内,继续设置定时器
            flag=true;
        }, delay);
    }
    //只要在delay时间内再次触发,就不能设置定时器
        flag=false;
    }
   
}
</script>
</html>

3

	可以看到,在持续触发事件的过程中,函数不会立即执行,并且每 0.8s 执行一次,在停止触发事件后,
函数还会再执行一次。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值