乐趣区

关于javascript:callapplybind函数详解

 咱们都晓得 call,apply,bind 函数都是为了扭转 this 的指向,那么对于三种函数有什么相同点有什么不太点或者有什么利用呢?上面咱们来进行介绍

call 与 apply 函数

 在 javascript 种,call,apply 的呈现是为了扭转函数体外部 this 的指向,上面咱们来看一个栗子,并从中进行剖析。

      var a = "我是 window 的小 a";
       var obj = {
           a:"我是 obj 的小 a",
           foo:function (...arg) {console.log(this.a,this,...arg)
           }
       }

       obj.foo()    // 此时的 this 为 obj

       var f2 = obj.foo
       f2()     // 此时的 this 为 window

       f2.call(obj,1,2,3)  //call 扭转了 this 的指向,此时的 this 为 obj, 并传入参数    
       f2.call(obj,[1,2,3]) // 输入 obj 中的 a
       f2.apply(obj,[1,2,3],3,4,5) //apply 扭转了 this 的指向为 obj, 传入参数数组, 在参数数组之后传递参数, 并不能传入该参数
       f2.apply(obj,1,2,3)  // 报错!apply 第二个参数必须为参数数组 

咱们来看一下输入后果。

 由上述输入后果来看,应用 call 和 apply 可能扭转 this 的指向。函数 f2 本来的指向为 window,应用 call 和 apply 函数绑定 obj 后 this 的指向为 obj。对于上述的输入后果还有一个报错?立马不淡定了。原来 apply 的第二个参数只能传入参数数组,不能传入多个参数。

对于上述输入后果的小总结为:

  • call 和 apply 都用于去扭转 this 的指向问题,第一个参数为 this 所指向的对象
  • call 和 apply 都为间接调用函数,返回值就为调用函数的返回值。
  • call 的第二个地位和之后传递参数列表,当向 call 中传递数组时,则视为只传递了一个参数 (这个参数为数组)
  • apply 的第二个地位只能传递参数数组,在参数数组之后传递参数,均生效。

依据 call 和 apply 的特点,咱们能够有以下利用。

应用 call 进行继承

 function father(name,age,hometown,hobby) {
            this.name = name;
            this.age = age;
            this.hometown = "中国"
            this.hobby = hobby;
        }
        function son(name,age,hobby,hometown) {father.call(this,name,age,hometown)// 继承父类中的多个属性
            this.hobby = hobby;
        }
        
        let f = new father("小头爸爸",38,"中国","钓鱼");
        let s = new son("大头儿子",16,"打球");
        
        console.log(f)
        console.log(s)

输入后果:

应用 call 判断数据类型

        console.log(Object.prototype.toString.call("pp"))
        console.log(Object.prototype.toString.call({age:15}))
        console.log(Object.prototype.toString.call(23))
        console.log(Object.prototype.toString.call([1,2,3]))


 在这我就不一一列举对于数据的数据类型了,此时必定有人产生纳闷,为什么平时咱们用的 obj.toString 和 object.prototype.toString.call(obj) 的后果为什么不一样了呢?因为咱们应用的 obj.toString() 在一些数据类型中都重写了 toString 的办法,对于函数和数组来讲,应用 obj.toString 都会间接输入字符串,故应用 obj.toString() 不能输入数据类型。但为什么 Object.prototype.toString.call(obj) 可能输入数据类型的值呢?因为 toString 为 Object 的原型办法,并没有像 obj.toString() 一样重写该办法。应用 Object 上的原型中的 toString 办法的返回值为数据类型。故咱们能够通过 Object.prototype.toString.call(obj) 来判断数据类型。

应用 call 使伪数组应用数组办法

     <div class="xixi"></div>
    <div class="xixi"></div>
    <div class="xixi"></div>
    <div class="xixi"></div>
    <script>
        // 将伪数组转换为数组, 使其能够调用数组所具备的办法
        var realArr = Array.prototype.slice.call(document.getElementsByTagName("div"));
        realArr.push(1)
        console.log(realArr)
        // 伪数组
        var div = document.getElementsByTagName("div")
        div.push(1)  // 报错为伪数组中没有数组具备的办法
    </script>

输出后果:

 对于咱们调用的一些办法例如 document.getElementsByName()、document.getElementsByTagName(),childNodes/children 等返回的均为伪数组,此时不能应用数组的办法, 咱们能够应用 call 函数使其转换为真正数组所带有真正数组办法的对象,这个时候咱们就可能调用数组的所有办法啦。

应用 apply 进行数组的连贯

        var arr1 = [1,"xixi",{age:17},34]
        var arr2 = [3,"haha",{age:44},21]
        Array.prototype.push.apply(arr1,arr2)// 进行数组的连贯
        console.log(arr1)

应用 apply 获取数组中的最大值

        var arr1 = [1,3,4,5,93]
        // 理论为向 Math.max 中传入参数 arr1, 等同于 Math.max(arr1)
        var max = Math.max.apply(Math.max,arr1)
        console.log(max)

bind 函数

 与 call 和 apply 类似,其作用都是用于扭转函数外部 this 的指向。但第二个参数开始是传入参数列表,这点与 call 类似,但与其有什么不同的中央呢?call 与 apply 是立刻执行函数而 bind 函数是将函数返回。

绑定函数

应用 bind 办法会返回一个函数,使其函数无论怎么调用,其 this 都会指向原来所绑定的那个对象

       var a = "我是 window 的小 a";
       var obj = {
           a:"我是 obj 的小 a",
           foo:function (...arg) {console.log(this.a,this,...arg)
           }
       }

       obj.foo()    // 此时的 this 为 obj

       var f1 = obj.foo()  // 此时的 this 为 window

       var f2 = f1.bind(obj)  // 绑定 this 为 obj, 并返回一个新函数
       f2() // 输入我是 obj 的小 a 

配合应用 setTimeout

在咱们没有给 setTimeout 绑定 this 的状况下,当咱们在 setTimeout 中应用 this,this 关键字会指向 window 对象,咱们能够利用 bind 函数绑定 this,使其可能利用 this 调用想要绑定的函数。

    function foo() {this.age = 20}
    // 函数 f1
    foo.prototype.f1 = function () {console.log(this)   // 此时的 this 为 foo
        setTimeout(this.f2,1000) // 然而此时的 this 为 window, 而不是 foo, 因而无奈调用 f2
        var _this = this   // 获取到以后的 this
        setTimeout(this.f2.bind(_this),1000) // 将 this.f2 的 this 绑定给 foo
    }
    // 函数 f2
    foo.prototype.f2 = function () {console.log("我的年龄为:" + this.age)
    }
    var foo = new foo()  // 发明实例
    foo.f1()

应用 bind 将类数组转换为数组

function foo() {

        var TempSlice = Array.prototype.slice;
        // 把函数的 call 办法绑定在数组 slice 办法上,之后再给 call 办法传递参数
        var slice = Function.prototype.call.bind(TempSlice);
        return slice(arguments);

    }
    console.log(foo(1,2,3))   //[1,2,3]

 

区别 bind()、call()、apply()

  • 都能指定函数中的 this
  • call() 和 apply 是立刻调用函数
  • bind() 是将函数返回

 
 
对于 bind(),cal(),apply() 的介绍就到这里啦,有帮忙的话就点个赞呗,欢送评论区斧正!

退出移动版