call,apply,bind的用法以及区别

163 阅读2分钟

作用:call、apply、bind的作用是改变函数运行时this的指向。

call

call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window。 如:

var arr = [1, 2,11,22]
var max = Math.max.call(null, arr[0], arr[1], arr[2], arr[3], arr[4])
//22

例子:

var obj = {
    name: "Tom"
}

var name = "Jack";

function myName (str, end) {
    console.log(str + this.name + end);
}
myName.call(obj, "my name is ", " !"); //my name is Tom !

myName("my name is ", " !"); //my name is Jack !

未绑定时,this在函数中默认绑定window,绑定后this指向绑定数据。

手写一个myCall:

    // 手写一个myCall
    let person = {
        getName: function () {
            return this.name;
        },
    };

    let person1 = {
        name: 'jock',
    };

    // 接受参数,改变this指向
    Function.prototype.myCall = function (context) {
        // context是第一个参数,改变后的this指向
        // this必须时函数
        if (typeof this !== 'function') {
            throw Error('绑定的不是函数');
        }

        // 默认是window
        context = context || window;
        // 拿到第一个之外的参数
        let args = [...arguments].slice(1);
        // 此时的this是绑定的函数,
        // console.log(this, '--this--')
        context.fn = this;
        // 改变执行上下文,此时的context.fn的this指向是context(此实例为person1)
        let result = context.fn(...args);
        // 去除fn
        delete context.fn;
        return result;
    }

    console.log(person.getName.myCall(person1, 1, 2, 3))

apply

apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window。 如:

var arr = [1, 21122];
var max = Math.max.apply(null,arr)//22

例子:

var obj = {
    name: "Tom"
}

var name = "Jack";

function myName (str, end) {
    console.log(str + this.name + end);
}
myName.apply(obj, ["my name is ", " !"]); //my name is Tom !

myName("my name is ", " !"); //my name is Jack !

上apply 和 call 的用法几乎相同, 唯一的差别在于:当函数需要传递多个变量时, apply 可以接受一个数组作为参数输入, call 则是接受一系列的单独变量。 手写一个myPlay:

// ...
 Function.prototype.myPlay = function(context) {
     // ...
     // 通myCall
 }

bind

和call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用。 bind返回值是函数,如:

var obj = {
    name: 'Dot'
}

function printName() {
    console.log(this.name)
}

var dot = printName.bind(obj)
console.log(dot) // function () { … }
dot()  // Dot

bind 方法不会立即执行,而是返回一个改变了上下文 this 后的函数。而原函数 printName 中的 this 并没有被改变,依旧指向全局对象 window。 手写一个bind: 基本通call、apply,只是将先执行改为后执行

    Function.prototype.myBind = function(context) {
        // ...同call,apply 
        return () => result;
    }

    let fn = person.getName.myBind(person1, 1, 2, 3);
    console.log(fn())

总结

call、apply和bind函数存在的区别: bind返回对应函数, 便于稍后调用; apply, call则是立即调用。

除此外, 在 ES6 的箭头函数下, call 和 apply 将失效, 对于箭头函数来说:

箭头函数体内的 this 对象, 就是定义时所在的对象, 而不是使用时所在的对象;