3

 我们都知道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()的介绍就到这里啦,有帮助的话就点个赞呗,欢迎评论区指正!


我的名字豌豆
406 声望746 粉丝

一起共同进步吧!