《call/apply/bind》

44 阅读1分钟

手写call

let obj = {name: '张三'};
let obj2 = {
  name: '李四',
  say: function(money1, money2){
    console.log(this.name);
    return money1 + money2;
  }
}

obj2.say.call(obj, 100, 200)  // 张三  300

// 函数原型链自定义call方法
Function.prototype.myCall = function(context){
  context = !context ? window : context;
  // 函数.myCall 所以this指向调用此方法的函数
  let fn = this;
  // 获取函数传入的参数
  let args = Array.prototype.slice.call(arguments, 1);
  // 将要指向的对象添加此函数
  context.fn = fn;
  // 对象调用函数
  let res = context.fn(...args);
  delete context.fn;
  return res;
}
obj2.say.myCall(obj, 200, 300)  // 张三 500    

手写apply

let obj = {name: '张三'};
let obj2 = {
  name: '李四',
  say: function(money1, money2){
    console.log(this.name);
    return money1 + money2;
  }
}

obj2.say.apply(obj, [100, 200])  // 张三  300


Function.prototype.myApply = function(context, arrParams){
  context = !context ? window : context;
  // 调用此方法的函数
  let fn = this;
  // 将要指向的对象添加此函数
  context.fn = fn;
  // 对象调用此函数
  let res = context.fn(...arrParams);
  delete context.fn;
  return res;
}

obj2.say.myApply(obj, [100, 200])  // 张三  300

手写bind

let obj = {name: '张三'};
let obj2 = {
  name: '李四',
  say: function(money1, money2){
    console.log(this.name);
    return money1 + money2;
  }
}

let fn = obj2.say.bind(obj, 100);
fn(200)      // 张三 300
new fn(200)  // say {} new 命令调用,this指向say的实例对象,并返回该实例对象

// 手写bind方法
Function.prototype.myBind = function(context){
  // 调用myBind的函数
  let fn = this;
  context = !context ? window : context;
  // 获得第一次调用传入的参数
  let args = Array.prototype.slice.call(arguments, 1);
  context.fn = fn;
  // 返回一个新函数
  return function(){
    // 获取调用bind返回的新函数时传入的参数
    let restArgs = Array.prototype.slice.call(arguments);
    let allArgs = args.concat(restArgs);
    let res = null;
    // 通过new调用的
    if(new.target){
      // 返回函数的实例对象
      return _new(fn, ...allArgs);
    }else{
      // 调用该函数
      res = context.fn(...allArgs);
    }
    return res;
  }
}

function _new(fn){
  console.log(arguments)
  var obj = Object.create(fn.prototype);
  var args = Array.prototype.slice.call(arguments, 1);
  fn.call(obj, ...args);
  return obj;
}

let fn2 = obj2.say.myBind(obj, 100);  
fn2(200)      // 张三 300
new fn2(200)  // say {}