1. 手写call函数
- 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 判断传入上下文对象是否存在,如果不存在,则设置为 window 。
- 处理传入的参数,截取第一个参数后的所有参数。
- 将函数作为上下文对象的一个属性。
- 使用上下文对象来调用这个方法,并保存返回结果。
- 删除刚才新增的属性。
- 返回结果。
Function.prototype.myCall = function(context){
//准备1:判断调用对象是否为函数
if(typeof this !== "function"){
console.error("type error");
}
// 准备2:判断 context 是否传入,如果未传入则设置为 window
context = context ||window;
// 准备3:获取参数
let args = [...arguments].slice(1);
// 1.将调用函数设为对象的方法
context.fn = this;
// 2.调用函数
let result = context.fn(...args);
// 3.将属性删除
delete context.fn;
return result;
}
2. 手写apply函数
- 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 判断传入上下文对象是否存在,如果不存在,则设置为 window 。
- 将函数作为上下文对象的一个属性。
- 判断参数值是否传入
- 使用上下文对象来调用这个方法,并保存返回结果。
- 删除刚才新增的属性
- 返回结果
Function.prototype.myApply = function(context){
if(typeof this !== "function"){
throw new TypeError("Error");
}
context = context || window;
let result = null;
context.fn = this;
if(arguments[1]){
result = context.fn(...arguments[1]);
}else{
result = context.fn();
}
delete context.fn;
return result;
}
3. 手写bind函数
3.1. 简陋版
- 在bind之前,我们已经了解了call和apply的实现,主要区别就是bind返回一个新的函数(具有原函数的功能)。
- 在绑定this之后,可以使用call或apply来表示那个返回的函数
Function.prototype.myBind = function(thisArg,...list){
let fn = this; // 目标函数
return function(...arg2){
return fn.apply(thisArg,[...list,...arg2])
}
}
// ---------------------------------------------------------
Function.prototype.myBind1 = function (...args) {
var thisFunc = this, thatObj = args[0];
args = args.slice(1);
return function (...arg) {
args = args.concat(arg);
return thisFunc.call(thatObj, ...args);
}
}
3.2. 完整版
- 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 保存当前函数的引用,获取其余传入参数值。
- 创建一个函数返回
-
函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。
Function .prototype.myBind = function(context){
if (typeof this !== "function") {
throw new TypeError("Error");
}
let args = [...arguments].slice(1), fn = this;
return Function Fn(){
return fn.apply(
this instanceof Fn ? this : context,args.concat(...arguments)
)
}
}
3.3. 终极版
既然返回的是一个函数,这个函数除了自调用,我们把它作为构造函数(也就是说使用new来调用)可以吗,按常理来说是可以的。原生 bind 函数也是可以实现的。
但此时的myBind函数创建的新函数并不能当做构造函数使用,为了解决此问题,我们需要将myBind函数中的prototype指向目标函数的prototype,constructor也需要指向目标函数(也就是手写一个继承)
Function.prototype.myBind = function(context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 获取参数
let args = [...arguments].slice(1)
let fn = this
let Fn = function Fn() {
return fn.apply(
this instanceof Fn ? this : context,
args.concat(...arguments)
)
// 将myBind函数中的prototype指向目标函数的prototype,constructor也需要指向目标函数(也就是手写一个继承
Fn.prototype = Object.create(fn.prototype)
Fn.prototype.constructor = fn
return Fn
}
}