|  
 call的特点 1.可以改变当前函数的this指向 2.可以让函数执行 Function.prototype.call = function (context) {
  // call是可以这样用的fn.call.call.call   如果调用的时候没传上下文,则context是window
  context = context ? Object(context) : window;
  context.fn = this; // 给context添加一个属性,待会儿要让它执行
  // call可以传多个参数 fn.call(obj1,1,2,3,4) 除第一个参数是要改变this的引用之外,剩下的都将作为参数
  let args = [];
  for (let i = 1; i < arguments.length; i++) {
    args.push(`arguments[${i}]`);
  }
  // 利用数组的toString特性 args会以逗号的形式展开 作为fn的参数
  let r = eval(`context.fn(${args})`);
  delete context.fn; 
  return r;
};
  
 ?apply的特点 1.与call原理类似,只是call的参数是多个,apply的参数是数组 Function.prototype.apply = function (context, args) {
  context = context ? Object(context) : window;
  context.fn = this;
  if (!args) return context.fn();
  for (let i = 1; i < arguments.length; i++) {
    args.push(`arguments[${i}]`);
  }
  let r = eval(`context.fn(${args})`);
  delete context.fn;
  return r;
};
 ? |