跳到主要内容

js 中 call apply bind 之间的关系

· 阅读需 4 分钟

说明

call(),apply(),bind() 函数大家可能都有所了解,但是在平时搬砖过程中很可能或者基本没用过,学过但都淡忘了。

但是在大量第三方的框架(库),甚至 js 自己都在 源码中大量使用 call,apply 函数。所以今天仔细讨论下它们在开发中的应用场景 。

这三个函数都是函数对象的方法,也就是说只有函数才可以直接调用这些方法。

作用

改变 this 的指向。或者说 强行用其他对象来调用一个函数(即时对象上面并没有这个方法)。

案例

function show(sex) {
console.log('姓名为' + this.yourname + ',性别为' + sex);
}
const person = {
yourname: '张三',
age: 14,
};
show.call(person, '男'); // 姓名为张三,性别为男
show('男'); // 姓名为 undefined,性别为男
person.show('男'); // 报错

在上面的代码块中,我们可以看到 person 对象并没有 show 方法,直接地用 person.show() 会报错。但是我们可以通过 call 方法来实现 person 对象来调用 show 方法。所以这种情况我认为就是改变了 this 的指向。

call, apply 和 bind 的区别

它们在功能上是没有区别的,都是改变 this 的指向,它们的区别主要是在于方法的实现形式和参数传递上的不同

  • 函数.call(对象,arg1,arg2....)
  • 函数.apply(对象,[arg1,arg2,...])
  • 函数.bind(对象,arg1,arg2,....)()
注意

bind 返回的是一个函数体,并不会直接执行函数

function show(sex) {
console.log('姓名为' + this.yourname + ',性别为' + sex);
}
const person = {
yourname: '张三',
age: 14,
};
// call
show.call(person, '男'); // 姓名为张三,性别为男
// apply
show.apply(person, ['女']); // 姓名为张三,性别为女
// bind 立即执行
show.bind(person, '未知')(); // 姓名为张三,性别为未知
// bind 需要的时候再执行
const showMethod = show.bind(person, '未知');
showMethod(); // 姓名为张三,性别为未知

实际应用

上述案例只是场景之一,列举一下他们常用的应用场景

处理伪数组(DOM NodeListgetElementsByTagName 等, arguments 参数)

const arr = document.getElementsByTagName('li');
arr.slice(1, 4); // 报错:TypeError -- arr.slice is not a function(slice不是函数)
Array.prototype.slice.call(arr, 1, 4); // 正常运行
// 或者 [].slice.call(arr,1,4); // 正常运行

call

call 的主要作用也可以实现继承

function Person(name) {
this.name = name;
}

function Man(name) {
Person.call(this, name);
}
const man = new Man('Zhang San');
console.log(man.name); // 'Zhang San'

apply

借助 apply 打散数组的功能我们可以实现求得数组中最大值

const arr = [1, 22, 3, 44, 5, 66, 7, 88, 9];
const max = Math.max.apply(Math, arr);
console.log(max); // 88

bind

bind 调用后返回已经绑定好 this 的函数,如上述 案例