关于call笔者之前在JS中THIS相关问题梳理这篇文章中已经讲过,但笔者觉得之前写的call方法不够惊艳😺,还有很多问题没有考虑到,这次重新整理一下,希望对您有帮助;

  1. let func = function (x, y) {
  2. console.log(this);
  3. return x + y;
  4. };
  5. window.name = "HELLO~";
  6. let obj = {
  7. name: '小芝麻'
  8. };
  9. func(10, 20); //=>this:window 'HELLO~' 30
  10. obj.func(10, 20); //=>Uncaught TypeError: obj.func is not a function
  11. 复制代码

需求:让func执行,需要让方法中的this变为objfuncobj本身还没啥关联)

// 实现思路:让func和obj关联在一起
// 1.给obj设置一个属性$func,让其属性值是函数func
// 2.obj.$func() 相当于把func执行了,此时方法中的this就是obj
// 3.这种操作方式会存在一些安全隐患:如果原有obj对象中就有$func的属性,我们设置的这个属性会覆盖原有的属性值[真实操作中,我们尽可能保证这个属性名的唯一性];我们设置的属性,在用完后,还要把它移除掉,因为人家对象原本是没有这个属性的;
// obj.$func = func;
// obj.$func(10, 20); //=>this:obj  '小芝麻' 30
// delete obj.$func;
// console.log(obj);
复制代码

代码实现

// 为了让每一个函数都可以调取这个方法了
Function.prototype.changeThis = function changeThis(context, ...args) {
  // THIS:当前要执行并且改变THIS指向的函数
  // CONTEXT特殊情况的处理:不传递是window,传递null/undefined也让其是window,传递非对象或者函数类型值,我们需要让其变为对象或者函数
  context == null ? context = window : null;

  //=> 为了过滤出传入参数是基本类型的情况
  if (typeof context !== "object" && typeof context !== "function") {
    //=> 运用构造函数常见一个基本数据类型的实例;
    //=> 目的是为了在下面context[uniqueKey] 时,由于基本数据类型不能运用对象的“点”或者“[]”存储属性时报错的问题
    context = new context.constructor(context);
  }
  //=> 利用模版字符串和时间戳生成一个唯一的属性名
  let uniqueKey = `?${new Date().getTime()}`;

  //=> 给参数中新增个uniqueKey属性与调用的函数关联
  context[uniqueKey] = this;

  //=> 让调用的函数执行
  let result = context[uniqueKey](...args);

  //=> 删除新增的属性
  delete context[uniqueKey];

  //=> 把函数执行的结果 return 出去
  return result;
};
let result = func.changeThis(obj, 10, 20);
let result = func.changeThis();
let result = func.changeThis(null/undefined);
let result = func.changeThis(10, 20); //=>方法执行,方法中的THIS是10,给方法传递了20(第一个参数是我们要改变的THIS指向问题)
复制代码

去除注释后的完整代码

Function.prototype.changeThis = function changeThis(context, ...args) {
  context == null ? context = window : null;
  if (typeof context !== "object" && typeof context !== "function") {
    context = new context.constructor(context);
  }
  let uniqueKey = `?${new Date().getTime()}`;
  context[uniqueKey] = this;
  let result = context[uniqueKey](...args);
  delete context[uniqueKey];
  return result;
};
let result = func.changeThis(obj, 10, 20);
let result = func.changeThis();
let result = func.changeThis(null/undefined);
let result = func.changeThis(10, 20); //=>方法执行,方法中的THIS是10,给方法传递了20(第一个参数是我们