call与apply中的this指向详解

67 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

每个函数都包含两个非继承而来的方法:call()和apply()

相同点:作用一样,call与apply都是设置函数中this的指向问题,以扩充函数赖以运行的作用域。

在对象调用方式时,一般来说此时this指向的是该方法所在的对象。但是使用call()和apply()后,this的指向就改变了。

不同点:两者的传参方式不同,call可以将该方法的参数分别作为自己的多个参数,如:obj1.method.call(obj,"参数1","参数2"),apply则是需要将该方法的参数合并成一个数组作为自己的一个参数,如obj1.method.apply(obj,["参数1","参数2"]),method就收到了参数1和参数2。

1.无参数时

无参数时,通过call()和apply()来指向this时,是将this的指向改为window。

/*
        无参数实现
        */
       var school = "A大学";
       var master = "通信";
       var person = {
        school: "B大学",
        master:"计算机",
        getDegree(){
            console.log("我在"+this.school+"取得了学士学位,我的专业为"+this.master);
        },
        getMajorCourse(course1,course2){
            console.log("我的主修课程有:"+course1+","+course2);
        }
       }
       // 如果直接调用call和apply,则this指向window。
       person.getDegree.call();
       person.getDegree.apply();

此时,输出是:

image.png

2.有参数时

/*
        有参数实现,this指向student
        */
        var school = "A大学";
        var master = "通信";
        var person = {
        school: "B大学",
        master:"计算机",
        getDegree(){
            console.log("我在"+this.school+"取得了学士学位,我的专业为"+this.master);
        },
        getMajorCourse(course1,course2){
            console.log("我的主修课程有:"+course1+","+course2);
        }
       }

       var student = {
           school:"C大学",
           master:"车联网",
       }
       person.getDegree.call(student);
       person.getDegree.apply(student);
       console.log("--------方法分割线--------");
       person.getMajorCourse.call(student,"课程1","课程2");
       person.getMajorCourse.apply(student,["课程1","课程2"]);

此时,输出是:

image.png

3.call(this,arguments)

/*
        call(this,arguments);
        this:指向当前所在的this指向
        argument:参数
        */
        var school = "A大学";
        var master = "通信";
        var person = {
        school: "B大学",
        master:"计算机",
        getDegree(){
            console.log("我在"+this.school+"取得了学士学位,我的专业为"+this.master);
        },
        getMajorCourse(course1,course2){
            console.log("我的主修课程有:"+course1+","+course2);
        }
       }

       var student = {
           school:"C大学",
           master:"车联网",
           getDegree(){
            console.log(arguments); //  ["课程111111111111", "课程22222222222",...]
            person.getDegree.call(student,arguments); // 我在C大学取得了学士学位,我的专业为车联网
            person.getDegree.call(this,arguments); // 我在C大学取得了学士学位,我的专业为车联网
            /*
            由于person.getDegree使用call改变this的指向,并在student对象中使用,此时this本身就指向student对象。
            所以,可写成person.getDegree.call(student,arguments);
            因此call(this,arguments)可以方便的应用于不同对象的方法,不需要每次修改对象。
            */
           person.getMajorCourse.call(this,arguments[0],arguments[1]); //我的主修课程有:课程111111111111,课程22222222222
        }
       }
       // 调用student对象的方法
       student.getDegree("课程111111111111","课程22222222222");

此时,输出是:

image.png

4.apply(this,arguments)

/*
        apply(this,arguments);
        this:指向当前所在的this指向
        argument:参数
        */
        var school = "A大学";
        var master = "通信";
        var person = {
        school: "B大学",
        master:"计算机",
        getDegree(){
            console.log("我在"+this.school+"取得了学士学位,我的专业为"+this.master);
        },
        getMajorCourse(course1,course2){
            console.log("我的主修课程有:"+course1+","+course2);
        }
       }

       var student = {
           school:"C大学",
           master:"车联网",
           getDegree(){
            console.log(arguments); //  ["课程111111111111", "课程22222222222",...]
            person.getDegree.apply(student,arguments); // 我在C大学取得了学士学位,我的专业为车联网
            person.getDegree.apply(this,arguments); // 我在C大学取得了学士学位,我的专业为车联网
            /*
            由于person.getDegree使用apply改变this的指向,并在student对象中使用,此时this本身就指向student对象。
            所以,可写成person.getDegree.apply(student,arguments);
            因此apply(this,arguments)可以方便的应用于不同对象的方法,不需要每次修改对象。
            */
           person.getMajorCourse.apply(this,arguments); //我的主修课程有:课程111111111111,课程22222222222
        }
       }
       // 调用student对象的方法
       student.getDegree("课程111111111111","课程22222222222");

此时,输出是:

image.png