前言
call、apply、bind在日常开发中多多少少都会使用到它们,下面让我们来深入比较并熟悉。
介绍
它们其实都是有两个共同点:
- 用于函数调用 :
call,bind, 和apply都用于调用函数。 - 设置函数上下文 :它们都允许您设置函数执行时的上下文对象(通常是函数内的
this)。
谈论到它们的区别的话,也是有两个不同的点:
- 参数传递方式 :
call: 接受一个函数的参数列表,依次传递给函数。apply: 接受一个函数的参数数组,其中数组的每个元素依次传递给函数。bind: 创建一个新的函数,将传递给bind的参数列表或数组绑定到函数上,并返回一个新函数,不立即执行。
- 立即执行 :
call和apply立即执行函数,它们会调用函数并传递参数。bind不会立即执行函数,它返回一个新函数,您需要显式调用该函数才会执行。
深入理解
我们现在来手写下它们,更好的熟悉下。
手写内容:
call
// call函数实现
Function.prototype.myCall = function (context) {
// 判断调用对象
if (typeof this !== "function") {
console.error("type error");
}
// 获取参数
let args = [...arguments].slice(1),
result = null;
// 判断 context 是否传入,如果未传入则设置为 window
context = context || window;
// 将调用函数设为对象的方法
context.fn = this;
// 调用函数
result = context.fn(...args);
// 将属性删除
delete context.fn;
return result;
};
apply
// apply 函数实现
Function.prototype.myApply = function (context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
let result = null;
// 判断 context 是否存在,如果未传入则为 window
context = context || window;
// 将函数设为对象的方法
context.fn = this;
// 调用方法
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
// 将属性删除
delete context.fn;
return result;
};
bind
// bind 函数实现
Function.prototype.myBind = function (context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 获取参数
var args = [...arguments].slice(1),
fn = this;
return function Fn() {
// 根据调用方式,传入不同绑定值
return fn.apply(
this instanceof Fn ? this : context,
args.concat(...arguments)
);
};
};
总结
以上手写是我们日常工作和面试中常常遇到的,手写它们有助于我们更深入的理解它们的作用和原理。