「✍ bind apply call」

166 阅读1分钟

call和apply

基本上就是入参格式的不同

const _call = function (context, ...resArgs) {
  context = context instanceof Object ? context : {};

  context["fn"] = this; 

  const result = context["fn"](...resArgs); // 带参执行

  delete context.fn;

  return result;
};

Function.prototype.call = _call
const _apply = function (context, resArgs) {
  context = context instanceof Object ? context : {};

  context["fn"] = this;

  const result = context["fn"](...resArgs); // 带参执行

  delete context.fn;

  return result;
};

Function.prototype.apply = _apply

call: 接收参数列表

call(context, ...resArgs) => context.fn(...resArgs)
call(obj, 1,2,3) => obj.fn(1,2,3)

apply: 接收数组

call(context, resArgs) => fn(context, ...resArgs)
call(obj, [1,2,3]) => obj.fn(1,2,3)

主要逻辑:

context["fn"] = this

this为调用call/apply的对象,即要执行的函数,赋值给传入的上下文

const result = context["fn"](...resArgs)

带参执行,此时函数执行的上下文已经变成了传入的context

delete context.fn;

删掉函数,避免污染传入的上下文

bind

const _bind = function (context, ...resArgs) {
  let fnc = this; // 获取要执行的函数

  return function () {
    fnc.call(context, ...resArgs, ...arguments); // 合并bind时的参数和调用函数时的参数
  };
};
Function.prototype.bind = _bind;

大同小异,只是返回的是待执行的函数

注:不能用arrow function, 不然获取不到执行函数this ~

more

上述重写都是挂载到原型上,也可以写成手动传入上下文,这种写法可以更好的作为模块导出

call (apply同上)

export const call = function (fnc: Function, context: any, ...resArgs) {
  context = context instanceof Object ? context : {};

  context["fn"] = fnc;

  const result = context["fn"](...resArgs); 

  delete context.fn;

  return result;
};

bind 使用上面写好的call

export const bind = function (fnc: Function, context, ...resArgs) {
  return function () {
    call(fnc, context, ...resArgs, arguments); 
  };
};

let obj = { name: 'jenson' }
function fn() { console.log(this.name) }
bind(fn, obj)() // jenson