apply、call和bind的作用和区别
apply与call
首先介绍一下apply与call,因为这两个方法的功能和使用方式都差不多,只是传参的方式不同。call和apply的作用都是改变函数运行时的上下文(context)
语法
fun.call(thisArg, arg1, arg2, ...)fun.apply(thisArg, argsArray)
参数
thisArg:在fun函数运行时this的指向
arg1, arg2, ...:传递给函数的参数列表
argsArray:一个数组或类数组对象,数组中的元素将被作为参数传递给函数。
示例
function fun(name, age) {console.log(name, age);}fun('张三', 18);fun.apply(this, ['张三', 18]);fun.call(this, '张三', 18);
将会输出同样的结果:
改变指向
window.name = 'windowName';const user = {name: 'userName',};function fun() {console.log(this.name);}fun(); // Cannot read properties of undefined (reading 'name')fun.apply(window); // windowNamefun.apply(user); // userName
判断元素类型
直接使用typeof进行类型判断时,并不能识别出Array和null,都会识别为object,因此需要使用Object.prototype.toString()方法
Object.prototype.toString.apply([1, 2]) // Array
Object.prototype.toString.call([1, 2]) // ArrayObject.prototype.toString.apply({}) // Object
Object.prototype.toString.call({}) // Object
注意:元素本身的toString()并不能打印出类型,只会输出元素的值
bind
bind与call和apply相似,但它不会立即执行函数,而是返回一个新的函数,这个新函数的this被永久绑定到第一个参数提供的值。
const user = {name: 'userName',};function fun() {console.log(this.name);}const res = fun.bind(user);res(); // userName
总结
call
方法
优势:
- 立即执行:
call
方法会立即调用函数,并允许你指定函数运行时的this
值。 - 参数列表:可以传递任意数量的参数,只需在
this
值之后依次列出即可。
区别:call
通过参数列表传递给函数,而不是数组。
apply
方法
优势:
- 立即执行:与
call
一样,apply
也会立即调用函数,并允许你指定函数运行时的this
值。 - 数组或类数组参数:
apply
可以接受一个数组(或类数组对象)作为参数,这使得当你需要传递大量参数时,apply
比call
更方便。
区别:apply
只接受两个参数,第二个参数必须是一个数组或类数组对象。
bind
方法
优势:
- 不立即执行:
bind
方法不会立即调用函数,而是返回一个新的函数,这个新函数的this
被永久绑定到提供的值。 - 预设参数:可以在绑定
this
的同时预设一些参数,使得新函数在调用时可以接收更多参数。
区别:
1. 执行时机:bind
不会立即执行函数,而是返回一个新的函数实例。
2. 多次调用:由于bind
返回的是一个新函数,你可以多次调用这个新函数,而call
和apply
在调用后即执行完毕。
综合比较
-
执行时机:
call
和apply
:立即执行函数。bind
:返回一个新的函数,可以在任何需要的时候调用。
-
参数传递:
call
:直接传递参数列表。apply
:传递一个包含所有参数的数组或类数组对象。bind
:可以在绑定this
的同时预设参数,并在调用时接收更多参数。
-
使用场景:
- 需要立即调用一个函数并指定
this
值时,使用call
或apply
。 - 需要创建一个新函数,以便在任何时候调用并预设
this
值和参数时,使用bind
。
- 需要立即调用一个函数并指定
总的来说,call
和apply
在功能上非常相似,主要区别在于参数传递的方式。而bind
则提供了更大的灵活性,它允许创建一个新的函数实例,可以延迟执行并预设参数。