三者都是改变函数的this指向,apply与call则是传递参数形式不同;apply和call是立即执行函数,bind则是需要调用执行。
Function.prototype.myApply = function (context) {
// 判断this是不是函数
if (typeof this != 'function') {
throw new TypeError("Not a Function");
}
// 函数执行的结果
let result;
// 传递的指向(实例对象)是否为空,为空默认window
context = context || window;
// 将当前方法保存为新的对象实例的方法
context.fn = this;
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
// 结束调用完之后删除实例对象的方法
delete context.fn;
// 返回函数执行结果
return result;
}
Function.prototype.myCall = function (context) {
// 判断this是否为函数
if (typeof this != 'function') {
throw new TypeError('Not a function');
}
// 函数执行结果
let result;
// 传递的指向(实例对象)是否为空,为空默认window
context = context || window;
// 保存当前方法为新的(指向)对象实例的方法
context.fn = this;
// 将参数列表转为参数数组,slice(1)去掉参数列表中的第一个传递指向的参数
let args = Array.from(arguments).slice(1);
result = context.fn(...args);
// 结束调用完之后删除实例对象的方法
delete context.fn;
// 返回函数执行结果
return result;
}
Function.prototype.myBind = function (context) {
// 判断this是否为函数
if (typeof this != 'function') {
throw new TypeError('Not a function');
}
// 保存调用bind的函数
const _this = this;
// 保存参数
const args = Array.prototype.slice.call(arguments, 1);
return function F() {
if (this instanceof F) {
// 如果是new出来的
// 返回一个空对象,且使创建出来的实例的__proto__指向_this的prototype,且完成函数柯里化
return _this(...args, ...arguments);
} else {
// 如果不是new出来的改变this指向,且完成函数柯里化
return _this.apply(context, args.concat(...arguments))
}
}
}