Skip to content

手写bind

你应该知道 bind/apply/call 的区别哈,那你能手写一个 bind 么? 我:wtf。。。。

bind

  • bind 方法会创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数(是的, bind 是有多个参数,只是我们平时只用一个)将作为新函数的预置参数,供调用时使用。

原版使用

javascript
// 浏览器环境
var a = 2;
function fn() {
  let a = 1;
  console.log(this.a);
  console.log(arguments);
}

let obj = {
  a: 3
};

const _fn = fn.bind(obj, [4, 5]);
_fn(6, 7); //  3   [[4,5],6,7]
fn(); // 2  undefined

手写一个 bind

js
Function.prototype.myBind = function (context) {
  let fn = this; // 保存 this 即当前调用的 fn

  // arguments 是一个独立的对象, 虽然长得像数组但他不是数组。 这里提供2种方式
  // 1.通过 call 取值
  // let args = Array.prototype.slice.call(arguments, 1); // 提取参数
  // 2.转为数组
  let params = Array.from(arguments).slice(1);
  // 当然也可以在定义函数时 使用  function (context,...args) {}
  // args = args ?? [];

  // 这里建议不写死参数 。因为无法判断 目标函数到底有多少参数
  return function () {
    // if (this instanceof newFn) {
    //   return new fn(...arguments, ...params);
    // }
    return fn.apply(context, [...params, ...arguments]);
  };
};

// 测试
var a = 2;
function fn() {
  let a = 1;
  console.log(this.a);
  console.log(...arguments);
}

let obj = {
  a: 3,
};

const _fn = fn.myBind(obj, [4, 5]);
_fn(6, 7, 8, 9); //  3   [ 4, 5 ] 6 7 8 9

let fn2 = {
  fn: function fn() {
    let a = 1;
    console.log(this.a);
    console.log(...arguments);
  },
};

const _fn2 = fn2.fn.bind(obj, [4, 5]);
_fn2(6, 7, 8, 9); //  //  3   [ 4, 5 ] 6 7 8 9

那 call / apply 呢?

js
// 注意是2个参数。 不能用  ...args
Function.prototype.myApply = function (context, args) {
  let fn = this;
  context['fn'] = fn;
  args = args ?? [];
  const res = context.fn(...args);
  return res;
};

// 一摸一样 就改了下参数
Function.prototype.myCall = function (context, ...args) {
  let fn = this;
  context['fn'] = fn;
  args = args ?? [];
  const res = context.fn(...args);
  return res;
};

var a = 2;
function fn() {
  let a = 1;
  return { a: this.a, args: arguments };
}

let obj = {
  a: 3,
};

console.log('my apply:', fn.myApply(obj, [1, 2, 3]));
console.log('origin apply:', fn.apply(obj, [1, 2, 3]));
// my apply: { a: 3, args: [Arguments] { '0': 1, '1': 2, '2': 3 } }
// origin apply: { a: 3, args: [Arguments] { '0': 1, '1': 2, '2': 3 } }

// ---

console.log('my call:', fn.myCall(obj, 1, 2, 3));
console.log('origin call:', fn.call(obj, 1, 2, 3));
// my call: { a: 3, args: [Arguments] { '0': 1, '1': 2, '2': 3 } }
// origin call: { a: 3, args: [Arguments] { '0': 1, '1': 2, '2': 3 } }