引用自https://blog.csdn.net/weixin_44494811/article/details/103486637

    1.介绍:首先我们要了解apply()的基本知识,apply()和call()都是每个函数或对象都拥有的非继承的方法。
    2.作用:都是用来改变this的指向的
    3.下面介绍带参数和不带参数的常见的应用
    首先想很好理解和应用apply,其根本是对于this的理解。
    this的三种指向:1.指向this所在函数的直接调用者,2.new的时候,指向new出来的对象,3.事件中指向当前的出发对象
    总结:this会指向某个对象
    为什么要用this?因为this的指向不是单一的,可以改变,可以代替将来的调用者,对于一个固定的函数,方便将来不同实例调用有不同结果,如果没有this,将来谁调用结果都是一样,达不到需求。
    先看看别人写的关于apply的理解,看完回来再看我这里,会收益匪浅
    菜鸟教程
    Js apply方法详解

    1. function Parent(name,age){
    2. this.name=name
    3. this.age=age
    4. console.log(this)
    5. console.log(this.name,this.age)
    6. }
    7. function Children(name,age,height){
    8. console.log(this,arguments)
    9. // Parent.apply(this,[name,age,height])
    10. // Parent(name,age)
    11. this.height=height
    12. }
    13. let lisi=new Children("李四",12,170)
    14. console.log(lisi.name,lisi.age,lisi.height)

    this指向,防抖函数中的fn.apply作用 - 图1
    上面的代码和输出,可以看到,children里面的this就是指children对象,argument就是传进来的参数。因为children中没有this.name=name和this.age=age,所以输出lisi.name和lisi.age都是undefined.
    在es5中我们想要继承parent中的属性,在这里换句话说,我们想要用parent中的this.name=name和this.age=age中的两行代码,一般我们首先想到的是,直接在children里面调用parent,我们就来试试可行性

    1. function Parent(name,age){
    2. this.name=name
    3. this.age=age
    4. console.log(this)
    5. console.log(this.name,this.age)
    6. }
    7. function Children(name,age,height){
    8. // console.log(this,arguments)
    9. // Parent.apply(this,[name,age,height])
    10. Parent(name,age)
    11. this.height=height
    12. }
    13. let lisi=new Children("李四",12,170)
    14. console.log(lisi.name,lisi.age,lisi.height)

    this指向,防抖函数中的fn.apply作用 - 图2
    结果输出,parent里面的this指向了window,虽然在children里面调用parent能接到两个参数name和age,在parent里面确实输出了李四和12,但是实例里面却是undefined,因为他仅存在parent中。那我们如何使用parent中的那两行代码呢或者说继承那两个属性。同样是调用parent如何才能使parent中的this指向children对象。明显是要改变this的指向,所以我们可以想到apply,call,bind等,这里用apply,其他的其实也是可以的。

    1. function Parent(name,age){
    2. this.name=name
    3. this.age=age
    4. console.log(this)
    5. console.log(this.name,this.age)
    6. }
    7. function Children(name,age,height){
    8. // console.log(this,arguments)
    9. Parent.apply(this,[name,age,height])
    10. // Parent(name,age)
    11. this.height=height
    12. }
    13. let lisi=new Children("李四",12,170)
    14. console.log(lisi.name,lisi.age,lisi.height)

    this指向,防抖函数中的fn.apply作用 - 图3
    现在看输出结果,实例对象lisi中有了‘李四’和12了,parent里面的this输出结果是children对象.这就达到我们想要的要求了。在children里面执行了 Parent.apply(this,[name,age,height]), Parent.apply(this,arguments)和 Parent.apply(this,[name,age,height])是一样的,区别在于一个可以随children参数如何变化自动接受参数,后者手动设置参数,相当于执行了this.name=name,this.age=age这两行代码了。并且this指向的是children。
    在节流防抖函数中,我们就会看到fun.apply(this,arguments)这样的一句话

    1. <div>
    2. 账户:<input type="text" id="myinput"><span id="tip"></span>
    3. </div>
    4. <script>
    5. function debounce(fun,wait=300){
    6. let timeout=null;
    7. return function(){
    8. if(timeout){
    9. clearTimeout(timeout)
    10. }
    11. timeout=setTimeout(()=>{
    12. fun.apply(this,arguments)
    13. // fun()
    14. },wait)
    15. }
    16. }
    17. let span=document.getElementById('tip')
    18. function testUname(){
    19. span.innerHTML="用户名合法"
    20. }
    21. let input=document.getElementById('myinput')
    22. addEventListener('input',debounce(testUname,1000))
    23. </script>

    这个是防抖函数,有了以上的经验,我们可以知道这里 fun.apply(this,arguments)的用意,无非就是想fun中的this指向debounce中return的这个函数中的this,return回来的这个函数中的this也就是指向直接调用return 函数那个对象。这里都是window来直接调用return回来的那个函数。所以这里的this其实没啥用,之所以这么写是因为arguments就是传入的参数数组,而且个数可以不确定的传回给fn。我们正常有参数的函数时fn(‘参数1’,‘参数2’,…)//这里的省略号不是正规语法,只是表示不确定个。这时候,如果我们项使fn内的this指向某个对象obj。那么我们的写法是fn.apply(obj,[‘参数1’,‘参数2’,…])这里的省略号不是正规语法,只是表示不确定个数。看一下下面例子:

    1. // var name='zhangsan'//let不上升到window
    2. window.name='zhangsan'
    3. function test2(num){
    4. console.log(this.name)
    5. console.log(num)
    6. }
    7. let obj={
    8. name:'lisi'
    9. }
    10. test2.apply(obj,[4])//lisi,4

    如果我们使test2具有防抖,并且给他传入1一个参数。我们这样调用debounce(test2)(6)//zhangsan 6
    正是因为我们不确定像test2这种将来使他具有防抖的函数有多少个参数。我们又知道arguments可以接受不确定的参数。但是我们又将这不确定的参数传给fn,能这样写吗,fn(argument),显然不行。因为fn接受的是fn(‘参数1’,‘参数2’,…)这种形式,而不是fn([‘参数1’,‘参数2’,…])。那怎么办,现在我们想到apply方法恰好就是接受这样的样式的。所以使用fn.apply(this,arguments)就顺理成章了。
    所以下面代码尝试多个参数;

    1. function debounce(fn){
    2. let timeout=null
    3. return function (){
    4. fn.apply(this, arguments);
    5. }
    6. }
    7. // var name='zhangsan'//let不上升到window
    8. window.name='zhangsan'
    9. function test2(num1,num2,num3){
    10. console.log(this.name)
    11. console.log(num1,num2,num3)
    12. }
    13. let obj={
    14. name:'lisi'
    15. }
    16. test2.apply(obj,[4])//lisi,4
    17. debounce(test2)(6,2,4)//zhangsan 6 2 4

    到这里,我们整理一下,问题就是两个,①不知道以后需要防抖的函数到底有多少个参数,用arguments来接受。②如何将arguments传回给需要防抖的函数。apply是一个恰到好处的应用。有这么一个思路了。我们可以设想用es6的…也可以方便的把参数传给fn。代码如下:

    1. function debounce(fn){
    2. let timeout=null
    3. return function (){
    4. // fn.apply(this, arguments);
    5. fn(...arguments)
    6. }
    7. }
    8. // var name='zhangsan'//let不上升到window
    9. window.name='zhangsan'
    10. function test2(num1,num2,num3){
    11. console.log(this.name)
    12. console.log(num1,num2,num3)
    13. }
    14. let obj={
    15. name:'lisi'
    16. }
    17. test2.apply(obj,[4])//lisi,4
    18. debounce(test2)(6,2,4)//zhangsan 6 2 4

    结果是一样的,所以证明了我们的想法。所以以后我们完全可以用下面那种更短小精悍容易理解的写法。
    ————————————————
    版权声明:本文为CSDN博主「前端小懒虫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_44494811/article/details/103486637