手写 js 原生函数系列

123 阅读1分钟

手写 js 原生函数系列

手写 call 函数

首先介绍 call 函数:call 函数会改变 this 指向

call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

举个栗子:

function add(a, b) {
  console.log(this, a, b);
  return a + b;
};

add.call({}, 1, 2); // {} 1 2

第一版

实现 call 函数功能的基本结构,用到的知识点:

  • 原型链

不足之处:

  • fn 可能和 ctx 中的属性重复
Function.prototype.call2 = function(ctx, ...args) {
  ctx.fn = this;
  ctx.fn(...args);
  delete ctx.fn;
}

function add(a, b) {
  console.log(this, a, b);
  return a + b;
};

add.call2({}, 1, 2); // { fn:[Function:add] } 1 2

第二版

用到的知识点:

  • Symbol
  • ES5 的属性描述符

不足之处:

  • call 的第一个参数可能为 null 或 undefined
Function.prototype.call2 = function(ctx, ...args) {
  let key = Symbol('temp');
  Object.defineProperty(ctx, key, {
    enumerable: false,
    value: this,
  });
  let result = ctx[key](...args);
  delete ctx[key];
  return result;
}

function add(a, b) {
  console.log(this, a, b);
  return a + b;
};

add.call2({}, 1, 2); // {} 1 2

最后一版

Function.prototype.call2 = function(ctx, ...args) {
  ctx = (ctx === null || ctx === undefined) ? globalThis : Object(ctx);
  let key = Symbol('temp');
  Object.defineProperty(ctx, key, {
    enumerable: false,
    value: this,
  });
  let result = ctx[key](...args);
  delete ctx[key];
  return result;
}

function add(a, b) {
  console.log(this, a, b);
  return a + b;
};

add.call2({}, 1, 2); // {} 1 2