1.call函数实现
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
思路:
-
根据call的规则设置上下文对象,也就是this的指向,
-
将函数的this指向隐式绑定到context上,
-
通过隐式绑定执行函数并传递参数。
-
删除临时属性,返回函数执行结果
Function.prototype.myCall = function (context, ...arr) {
// 指定为 null 和 undefined 的 this 值会自动指向全局对象(浏览器中为window)
(context === null || context === undefined) ? window : Object(context);
const specialPrototype = Symbol('特殊属性Symbol'); // 用于临时储存函数
context[specialPrototype] = this; // 函数的this指向隐式绑定到context上
let result = context[specialPrototype](...arr); // 通过隐式绑定执行函数并传递参数
delete context[specialPrototype]; // 删除上下文对象的属性
return result; // 返回函数执行结果
};
2.apply函数实现
apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
思路:
- call是apply的语法糖,传递参数方式不一样,对其参数进行处理
Function.prototype.myApply = function (context) {
(context === null || context === undefined) ? window : Object(context);
// JavaScript权威指南判断是否为类数组对象
function isArrayLike(o) {
if (o && // o不是null、undefined等
typeof o === 'object' && // o是对象
isFinite(o.length) && // o.length是有限数值
o.length >= 0 && // o.length为非负值
o.length === Math.floor(o.length) && // o.length是整数
o.length < 4294967296) // o.length < 2^32
return true
else
return false
}
const specialPrototype = Symbol("特殊属性Symbol")
context[specialPrototype] = this; // 隐式绑定this指向到context上
let args = arguments[1]; // 获取参数数组
let result
// 处理传进来的第二个参数
if (args) {
// 是否传递第二个参数
if (!Array.isArray(args) && !isArrayLike(args)) {
throw new TypeError('myApply 第二个参数不为数组并且不为类数组对象抛出错误');
} else {
args = Array.from(args) // 转为数组
result = context[specialPrototype](...args); // 执行函数并展开数组,传递函数参数
}
} else {
result = context[specialPrototype](); // 执行函数
}
delete context[specialPrototype]; // 删除上下文对象的属性
return result; // 返回函数执行结果
};
3.bind函数实现
bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。
思路:
- 拷贝源函数
- 构造一个中间函数,其内通过instanceof判断函数是否通过new调用,来决定绑定的context
- 在这中间函数中用apply调用源函数,并且传入两次所传递的参数
- 将源函数的prototype链接给中间函
- 返回这个中间函数
Function.prototype.myBind = function (objThis, ...params) {
const thisFn = this; // 存储源函数以及上方的params(函数参数),thisFn=>被绑定的函数
// 对返回的函数 secondParams 二次传参
let fToBind = function (...secondParams) {
const isNew = this instanceof fToBind // this是否是fToBind的实例
// new调用就绑定到this上,否则就绑定到传入的objThis上
const context = isNew ? this : Object(objThis)
// 用apply调用源函数绑定this的指向并传递参数,返回执行结果
return thisFn.call(context, ...params,...secondParams);
};
fToBind.prototype = Object.create(thisFn.prototype); // 复制源函数的prototype给fToBind
return fToBind; // 返回拷贝的函数
};
参考来源: