call\apply\bind实现原理解析

2022 年 4 月 5 日 星期二(已编辑)
/
9
这篇文章上次修改于 2024 年 7 月 20 日 星期六,可能部分内容已经不适用,如有疑问可询问作者。

call\apply\bind实现原理解析

fn.call方法原理

Function.prototype.v2call = function (thisArg, ...args) {
  //目的:将传入的thisArg对象作为调用v2call的函数的this指向

  //使用fn变量存储this 此时fn指向调用v2call的函数对象 这里是foo
  var fn = this;
  //边界判断 如果不为空 将原始字面量转化为实例对象 否则thisArg指向window
  thisArg = thisArg ? Object(thisArg) : window;
  //thisArg新增fn属性引用函数对象fn
  thisArg.fn = fn;
  args = !isNone(args) ? args : [];
  //隐式绑定: 函数在不同上下文调用时会影响this的指向
  //此时在thisArg上下文中调用时fn的this会绑定thisArg
  var res = thisArg.fn(...args);
  //做完删除fn
  delete thisArg.fn;
  //返回函数调用的返回值
  return res;
};
function isNone(v) {
  return v === undefined || v === null
}
var a = '这是全局的a';
function foo() {
  console.log('this指向:', this);
  var sum = Array.prototype.reduce.call(
    arguments,
    (pre, cur) => {
      return pre + cur;
    },
    0
  );
  console.log('value:', sum);
  return sum;
}
var obj = {
  a: '这是obj对象里的a',
};
console.log(foo.v2call(obj, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

输出结果:

77b30a406e58d0308b71d80082b59889

77b30a406e58d0308b71d80082b59889

fn.apply方法原理

Function.prototype.v2apply = function (thisArg, args) {
  //目的:将传入的thisArg对象作为调用v2call的函数的this指向

  //使用fn变量存储this 此时fn指向调用v2call的函数对象 这里是foo
  var fn = this;
  //边界判断 如果不为空 将原始字面量转化为实例对象 否则thisArg指向window
  thisArg = thisArg ? Object(thisArg) : window;
  //关键: 利用隐式绑定: 函数的调用方式会影响this的指向
  //thisArg新增fn属性引用函数对象fn
  thisArg.fn = fn;
  //此时在thisArg上下文中调用时fn的this会绑定thisArg
  args = !isNone(args) ? args : [];
  var res = thisArg.fn(...args);
  //做完删除fn
  delete thisArg.fn;
  //返回函数调用的返回值
  return res;
};
function isNone(v) {
  return v === undefined || v === null
}
var a = '这是全局的a';
function foo() {
  console.log('this指向:', this);
  var sum = Array.prototype.reduce.call(
    arguments,
    (pre, cur) => {
      return pre + cur;
    },
    0
  );
  console.log('value:', sum);
  return sum;
}
var obj = {
  a: '这是obj对象里的a',
};
console.log(foo.v2apply(obj, [1, 2, 3, 4,5]));

输出结果:

d03c30e655d8b1c70bf2ae93c27ca630

d03c30e655d8b1c70bf2ae93c27ca630

fn.bind 方法原理

Function.prototype.v2bind = function (thisArg, ...argsArr) {
  //目的:将传入的thisArg对象作为调用v2call的函数的this指向,并返回这个函数,且传入的参数可先固定

  //使用fn变量存储this 此时fn指向调用v2call的函数对象 这里是foo
  var fn = this;
  //边界判断 如果不为空 将原始字面量转化为实例对象 否则thisArg指向window
  thisArg = thisArg ? Object(thisArg) : window;
  function proxyFn(...args) {
    thisArg.fn = fn;
    var concatParams = [...argsArr, ...args];
    //隐式绑定: 函数在不同上下文调用时会影响this的指向
    //此时在thisArg上下文中调用时fn的this会绑定thisArg
    var res = thisArg.fn(...concatParams);
    //调用完删除fn
    delete thisArg.fn;
    //返回fn返回值
    return res;
  }
  //返回这个绑定this后的函数
  return proxyFn;
};
function isNone(v) {
  return v === undefined || v === null;
}
var a = '这是全局的a';
function foo() {
  console.log('this指向:', this);
  var sum = Array.prototype.reduce.call(
    arguments,
    (pre, cur) => {
      return pre + cur;
    },
    0
  );
  console.log('value:', sum);
  return sum;
}
var obj = {
  a: '这是obj对象里的a',
};
var bindFn = foo.v2bind(obj, 1, 2, 3, 4, 5);
console.log(bindFn);
console.log(bindFn(6, 7, 8, 9, 10));

输出结果:

ca844c6114193b8dea5d05161ddae1f8

ca844c6114193b8dea5d05161ddae1f8

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...