重写内置的call的关键是把要执行的函数和和需要改变的THIS关联在一起
也就是给Function.prototype.call重新写一个函数。
Function.prototype.call = function call(context, ...params) {
// this->fn context->obj params->[10,20]
context == null ? context = window : null;
// 需要保证context必须是对象类型的值:只有对象才能设置属性
!/^(object|function)$/.test(typeof context) ? context = Object(context) : null;
let self = this,
result = null,
key = Symbol('KEY'); //新增的属性名保证唯一性,防止污染了原始对象中的成员
context[key] = self;
result = context[key](...params);
delete context[key]; //用完后移除自己新增的属性
return result;
};
function fn(x, y) {
console.log(this, x, y);
}
let obj = {
name: 'Lily',
fn: 87
};
fn.call(obj, 10, 20);
重写bind,bind和call的区别就是bind是预处理this,等触发才会执行
Function.prototype.bind = function bind(context, ...outerArgs) {
// this->fn context->obj outerArgs->[10,20]
let self = this;
return function(...innerArgs) {
// innerArgs->[ev]
self.call(context,...outerArgs.concat(innerArgs));
};
};
function fn(x, y, ev) {
console.log(this, x, y, ev);
}
let obj = {
name: 'happy'
};
document.body.onclick = fn.bind(obj, 10, 20);
对比一下自己重写的bind和call,可以发现返回值不一样,bind函数里面用了预处理的思想,和闭包中的柯里化函数类似。