call、apply、bind 用法和区别

js 中,每个函数的原型都指向Function.prototype对象,因此,每个函数都会有apply,call,和bind方法,这些方法继承于Function,都是用于改变函数执行时的上下文,从而改变函数中的this指向。

首先看一个例子

var info = {
    name: "小王",
    city: "黄冈",
    age: 20,
    say: function(hobby) {
        console.log(`${this.name}, 来自${this.city}, 今年${this.age}岁了, 喜欢${hobby}`)
    }
}

var info2 = {
    name: "小红",
    city: "黄冈",
    age: 18
}

info.say('足球') // 小王, 来自黄冈, 今年20岁了, 喜欢足球

info.say.call(info2, '足球')  // 小红, 来自黄冈, 今年18岁了, 喜欢足球

info.say.apply(info2, ['足球']) // 小红, 来自黄冈, 今年18岁了, 喜欢足球

info.say.bind(info2, '足球')   // 无输出结果

info.say.bind(info2, '足球')() // 小红, 来自黄冈, 今年18岁了, 喜欢足球

 以上例子得知, call()、apply()、bind()  都改变了函数 this 的上下文。

一、call 用法

fn.call(thisArg, arg1, arg2, arg3, ...)

调用fn.call时会将fn中的this指向修改为传入的第一个参数thisArg;将后面的参数传入给fn,并立即执行函数fn。

二、apply 用法 

apply(thisArg, [argsArr])

fn.apply的作用和call相同:修改this指向,并立即执行fn。区别在于传参形式不同,apply接受两个参数,第一个参数是要指向的this对象,第二个参数是一个数组,数组里面的元素会被展开传入fn,作为fn的参数。

三、bind 用法 

bind(thisArg, arg1, arg2, arg3, ...)

fn.bind的作用是只修改this指向,但不会立即执行fn;会返回一个修改了this指向后的fn。需要调用才会执行:bind(thisArg, arg1, arg2, arg3, ...)()  bind的传参和call相同

call,apply,bind 区别

相同点:
三个都是用于改变this指向;
接收的第一个参数都是this要指向的对象;
都可以利用后续参数传参。
 

不同点:
call和bind传参相同,多个参数依次传入的;
apply只有两个参数,第二个参数为数组;
call和apply都是对函数进行直接调用,而bind方法不会立即调用函数(要手动调用下,前两个是主动调用),返回是修改this后的函数。


修改this的性质不同:
call、apply只是临时的修改一次,也就是call和apply方法的那一次;当再次调用原函数的时候,它的指向还是原来的指向。
bind是永久修改函数this指向,它修改的不是原来的函数;而是修改过后新的函数,此函数的this永远被改变了,绑定了就修改不了。

提示 

如果你要传递的参数不多,则可以使用fn.call(thisObj, arg1, arg2 …)

如果你要传递的参数很多,则可以用数组将参数整理好调用fn.apply(thisObj, [arg1, arg2 …])

总结

综上所述,call,apply和bind的区别就是为了改变this的上下文而存在的,因此,有时候你会看到这样的用法。为了不改变this的指向,通常会在函数后边加上bind(this),如下:

function f(){}.bind(this) 这样的话,就不会出现莫名其妙的this指向问题了。

其实,从es6开始,已经支持箭头函数了,我建议大家用箭头函数,就不会出现this指向的问题了。  另外,使用call,apply还可以实现函数的继承。在es6的class没有出现之前,就需要借助它们来实现继承关系。

猜你喜欢

转载自blog.csdn.net/qq_34402069/article/details/127230475