The difference between apply, call, and bind—attachment: anti-shake, throttling function

The difference between apply, call, and bind

The same point
1.1 The three can change the point of this in the function
1.2 The first parameter is the object pointed to by this to be changed
Difference
2.1, The second parameter: apply is passed an array of parameters; call and bind are passed The parameter list, and apply and call are passed in at one time, and bind can be passed in multiple times.
2.2, bind returns the function after binding this, which needs to be called. apply and call are executed immediately.
How can I just talk about the summary, the above example:

Basic data:

	let name = = "lucky";
	const obj = {
    
    
	   	name: "martin",
	  	say: function (content = "") {
    
    
	   		console.log(this.name + content,"---",this);
		},
		hobby: function(content1="", content2="") {
    
    
        	console.log(`${
      
      this.name}喜欢${
      
      content1}${
      
      content2? '和':''}`+ content2,"---",this);
      	},
      	play: function(content1="", content2="") {
    
    
        	console.log(`${
      
      this.name}喜欢打${
      
      content1}${
      
      content2? '和':''}`+ content2,"---",this);
      	}
	};
	obj.say(); //martin,this指向obj对象
	

The following example: all three can change the this point in the function, and the first parameter is the object to be changed by this point.

	//这个指向obj, 也是因为是obj调用了这个方法
    obj.say("你好"); //martin你好 this指向obj对象
    
    // this指向window对象, 因为call改变了它的指向
    obj.say.call(null, "你好"); //lucy你好 
    obj.say.apply(null, "你好"); //lucy你好 
    obj.say.bind(null, "你好"); //lucy你好 
    

The following example: apply passes an array of parameters; call and bind pass a list of parameters.

	obj.hobby.call(null, "吃","喝")//lucy喜欢吃和喝
    obj.hobby.apply(null, ["吃2","喝2"])//lucy喜欢吃和喝
    obj.hobby.bind(null, "吃3","喝3")lucy喜欢吃和喝

The following example: call and apply are executed immediately, and bind returns a function after binding, which needs to be called before it is executed.

	obj.play.call(null, "乒乓球3","豆豆");//lucky喜欢打乒乓球3和豆豆
	obj.play.apply(null, ["乒乓球3","豆豆"]);//lucky喜欢打乒乓球3和豆豆

    let play2 = obj.play.bind(null, "羽毛球3","豆豆"); //此不会执行打印,需要作以下调用
    play2();//lucky喜欢打羽毛球3和豆豆
    

The following example: bind can pass parameters multiple times:
1. Parameters can be passed at the time of binding;
2. Parameters can also be passed at the time of calling;
3. Some of them can be passed at the time of calling, and some of them can be passed at the time of binding. Notes The bound parameters will not change, and the parameters passed when calling can only be passed in after the bound parameters;

	
	// 1、绑定时传参  [注] bind的时候如果绑定参数,调用的时候再传参也不会被改变
    let play3 = obj.play.bind(null, "王者1","豆豆");
    play3();//lucky喜欢打王者1和豆豆
    //下面打印就是因为绑定的时候参数也被绑定了,所以打印的是绑定时的内容 
    play3("王者2","豆豆");//lucky喜欢打王者1和豆豆
	
	// 2、调用时传参
	let play5 = obj.play.bind(null);
	play5("王者2","豆豆2");//lucky喜欢打王者2和豆豆2
	
	/* 
      3、调用的时候传参,已经被绑定的参数不变, 调用时传的参会从绑定的参之后直接顺位下去,如下所示:
      第一个参数已绑定,调用时的第一个参数直接变成第二个参数
    */
	let play4 = obj.play.bind(null,"王者3");
    play4("王者4","豆豆");//lucky喜欢打王者3和王者4 
    

The following is the relevant knowledge of setTimeout.

	/* 
      setTimeout的第一个参数是将要执行的代码或者函数名
      obj.say,其实是传了一个方法进去,执行方法,此时是在全局执行上下文的环境中执行
      所以它指向window对象
    */
    setTimeout(obj.say, 0); //lucy,this指向window对象

    // 这个指向obj, 是因为是obj调用了这个方法(与下同)
    setTimeout(() => {
    
    
      obj.say();
    })
	//这个指向obj, 也是因为是obj调用了这个方法
    setTimeout(obj.say("你好"), 0); //martin你好 this指向obj对象
    

Throttle function and anti-shake function

Below is the base code

<body>
	<div>
		<!-- 节流函数 -->
	    <button onclick="handleThrottle1(num1, num2, num3)">时间差节流函数</button>
	    <button onclick="handleThrottle(obj)">setTimeout节流函数</button>
	
	    <!-- 不用apply 会出现的问题 -->
	    <button onclick="foo.bar()">节流函数改变this指向</button>
	
	    <!-- 防抖函数 -->
	    <button onclick="handleDebounce(num1, num2, num3)">防抖函数</button>
	</div>
</body>

	//javascript 代码
	let num1 = 1;
	    num2 = 2;
	    num3 = 3;
	const obj = {
    
    
	   name: "cjj",
	   age: 18
	}
	

Throttling function : prevent a function from being called continuously in a short period of time, [execute only once within the set time] to prevent frequent user behaviors from causing the program to crash and affect the experience. See the following example in detail:

   // 方法一 时间差法 节流函数
   function throttle1(fn, wait) {
    
    
     let pre = new Date().getTime();
     return function(...args) {
    
    
       let now = new Date().getTime();
       if(now - pre >= wait) {
    
    
         
         fn.apply(this, args);//将this正确指向
         // fn(...args);
         console.log(this.obj,"----打印obj---")
         pre = new Date().getTime();
        
       }
     }
   }
   //需要节流的函数
   function myFn(arg1, arg2, arg3) {
    
    
     console.log("----打印成功----", arg1, arg2, arg3);
   }
   //触发事件
   const handleThrottle1 = throttle1(myFn,2000);
   
	
	// 方法二 setTimeout方法 节流函数
    function throttle(fn, wait) {
    
    
      let timer = null
      return function(...args) {
    
    
        if(!timer) {
    
    
          // fn(...args);
          fn.apply(this, ...args);//将this正确指向
          timer = setTimeout(()=> {
    
    
            timer = null
          }, wait)
        }
      }
    }
    //需要节流的函数
    function myObjFn(obj) {
    
    
      console.log(obj,"----打印---");
    }
    //触发事件
    const handleThrottle = throttle(myObjFn,2000);
    

Anti-shake function : event delay time trigger. During the delay time, the event is triggered again and the delay time will be recalculated. The popular point is: the event will be delayed only once it is triggered, and it will be executed for the last time if it is triggered more than once. See the following example in detail:

	//防抖函数
	function debounce(fn, wait) {
    
    
      let timer = null;
      return function (...args) {
    
    
        if(timer) {
    
    
          clearTimeout(timer);
        }
        timer = setTimeout(() => {
    
    
          fn(...args);
          time = null;
        }, wait)
      }
    }
    //需要防抖的函数
	function MF(arg1, arg2, arg3) {
    
    
      console.log("-----防抖----", arg1, arg2, arg3);
    }
    //触发事件
    const handleDebounce = debounce(MF, 1000);

    

In most cases, it seems that throttling and anti-shake effects can be achieved without using methods such as apply, so can I directly call the method without changing the this point? In fact, in some cases, if you do not use functions such as apply, it will cause problems with this pointing, so it is still necessary to change this pointing. Let me illustrate with an example:

	// 节流函数
	function throttle(fn, wait) {
    
    
      let timer = null
      return function(...args) {
    
    
        if(!timer) {
    
    
          // fn(...args);
          fn.apply(this, ...args);//将this正确指向
          timer = setTimeout(()=> {
    
    
            timer = null
          }, wait)
        }
      }
    }
	// 使用apply的理由
    class Foo {
    
    
      constructor() {
    
    
        this.a = "a";
        this.bar = throttle(this.bar, 500);
      }
      bar() {
    
    
      	/* 
      	  具体可修改上面throttle方法内的fn的注释,二选一即可
          如果节流函数使用 fn(...args) 下面打印的this是 undefined, this.a会报错
          如果节流函数使用 fn.apply(this, ...args); 下面打印的this是 实例化的对象foo, this.a 是 "a"
        */
        console.log(this,"----this----");
        console.log(this.a,"----a----");
      }
    }
    const foo = new Foo();
    

insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/weixin_46653360/article/details/130305298