简述call( )、apply( )、bind( )

389 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情

JavaScript为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部this的指向问题,常用的有bind()、call()、apply()三种方法

这三个方法呢,他们的作用是改变函数执行时的上下文,emmm,就是改变函数运行时的this指向
关于this指向,俺之前有写过,诶嘿嘿

call、apply、bind都是Function对象的原型方法,它们是把特定的函数当作一个方法绑定到指定的对象上进行调用。最终的返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。

call()方法

call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this指向

语法:函数名.call(thisArg,arg1,arg2...)
thisArg就是指定的对象,后面对应函数中的参数
案例:

        var o = {
            name: 'andy'
        }

        function fn(a, b) {
            console.log(this);
            console.log(a + b);
        };

        fn.call(o, 1, 2);

上面代码输出了this的指向以及 3 这个值。

apply()方法

同样的apply()方法调用一个函数。简单理解为是一种调用函数的方式 ,它也是可以改变this指向。

语法:函数名.apply(thisArg,[argsArray]);
thisArg就是指定的对象,但是第二个参数,必须是数组

案例:

        var o = {
            name: 'andy'
        };

        function fn() {
            console.log(this);
            console.log(arguments);
        };

        fn.apply(o,['ace','luffy']); // ①
        fn(['ace','luffy']); // ②

以上代码,最后输出了this的指向,也就是o,然后看下面图片
①的结果:
image.png
②的结果:
image.png

通过内置对象argument输出获取的参数,两种调用方式对比后可以发现:
apply的精髓其实在于把传入的数组打碎变成参数列表,然后再把这个参数列表传递给你调用的函数

来看看apply方法主要应用,比如我们可以利用apply传一个数组,利用内置对象Math中的max()或者min()方法去求数组的最大或最小值。因为我们数组本身没有最大最小值的方法呀

        var arr = [1, 66, 4, 88, 99];
        // var max = Math.max.apply(null, arr);
        var max = Math.max.apply(Math, arr);
        console.log(max); //99

我们调用的是数学对象中的方法,不需要改变指向,所以传null,其实最好把null改为Math,指回去。
(诶嘿嘿,其实利用扩展运算符也可以,直接Math.max(...arr) ^_^ )

bind()方法

bind()方法呢不会调用函数,但是能够改变函数内部this指向

语法:函数名.bind(thisArg,arg1,arg2,...) thisArg就是你指定的对象,arg1这些是参数

→ bind返回的是由指定的对象和初始化参数改造的原函数拷贝! ←

案例1:

    var o = {
            name: 'andy'
        }

        function fn(a, b) {
            console.log(this);
            console.log(a + b);
        };
        fn.bind(o);
        

只这样写是不会调用函数fn的,这样只是让fn临时成为指定对象下的方法
刚刚我们说过,bind返回的是一个函数,我们可以试着接收一下

        var f = fn.bind(o, 1, 2);
        f(); //this指向了o,并输出了3

案例2

来看看bind()方法的应用场景,如果有的函数不需要立即调用,但又想改变函数内部this指向
比如,我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮

        var btn = document.querySelector('button');
        btn.onclick = function () {
            this.disabled = true;
            // var that = this;    ②
            setTimeout(function () {
                this.disabled = false;  // ①
                // that.disabled = false    ③
            }.bind(this), 3000);
        }

以上这么写。
问题①:setTimeout是window下的方法,this指向的是window,不会让这个按钮恢复
解决方案②、③:正常的写法就是在setTimeout方法外面用一个变量保存this的值,然后在定时器中调用这个变量即可。

👇来看看利用bind方法怎么写👇

    var btn = document.querySelector('button');
        btn.onclick = function () {
            this.disabled = true;
            setTimeout(function () {
                this.disabled = false;
            }.bind(this), 3000);       // }.bind(btn), 3000);
        }

btn不方便,可以用this,因为这个bind还是在btn这个对象里面,所以bind(this)指向的是btn
因为这个定时器临时成为btn对象中的一个方法,这样相当于是btn调用的,内部的this指向的是btn
就能 成功实现我们要的效果!